INTRO¶

Notebook for applying Data Assimilation on seasonal data (Lutetian reconstructions)¶

Assemble data in the proxy domain using offline (block update) assimilation instead of point-by-point¶

Assemble data in SST (D47), SAT (D47), SSS (d18Oc) and precipitation domain¶

Comparison between different models with different pCO2 forcing¶

Author: N.J. de Winter (n.j.de.winter@vu.nl)
Assistant Professor Vrije Universiteit Amsterdam

References used in coding

Data assimiliation

  • Steiger, N.J., Hakim, G.J., Steig, E.J., Battisti, D.S., Roe, G.H., 2014. Assimilation of Time-Averaged Pseudoproxies for Climate Reconstruction. Journal of Climate 27, 426–441. https://doi.org/10.1175/JCLI-D-12-00693.1
  • Hakim, G.J., Emile-Geay, J., Steig, E.J., Noone, D., Anderson, D.M., Tardif, R., Steiger, N., Perkins, W.A., 2016. The last millennium climate reanalysis project: Framework and first results. Journal of Geophysical Research: Atmospheres 121, 6745–6764. https://doi.org/10.1002/2016JD024751
  • King, J., Tierney, J., Osman, M., Judd, E.J., Anchukaitis, K.J., 2023. DASH: a MATLAB toolbox for paleoclimate data assimilation. Geoscientific Model Development 16, 5653–5683. https://doi.org/10.5194/gmd-16-5653-2023
  • Judd, E.J., Tierney, J.E., Lunt, D.J., Montañez, I.P., Huber, B.T., Wing, S.L., Valdes, P.J., 2024. A 485-million-year history of Earth’s surface temperature. Science 385, eadk3705. https://doi.org/10.1126/science.adk3705

Data sources

  • Van Horebeek, N., de Winter, N. J., Baatsen, M., Ziegler, M., Speijer, R. P., Vellekoop, J.: A European Monsoon-like climate in a Warmhouse World, Nature Communications, in review, 2025.
  • Baatsen, M., von der Heydt, A.S., Huber, M., Kliphuis, M.A., Bijl, P.K., Sluijs, A., Dijkstra, H.A., 2020. The middle to late Eocene greenhouse climate modelled using the CESM 1.0.5. Climate of the Past 16, 2573–2597. https://doi.org/10.5194/cp-16-2573-2020

Calibration equations

  • Harwood, A. J. P., Dennis, P. F., Marca, A. D., Pilling, G. M., and Millner, R. S.: The oxygen isotope composition of water masses within the North Sea, Estuarine, Coastal and Shelf Science, 78, 353–359, https://doi.org/10.1016/j.ecss.2007.12.010, 2008.
  • Daëron, M. and Vermeesch, P.: Omnivariant generalized least squares regression: Theory, geochronological applications, and making the case for reconciled Δ47 calibrations, Chemical Geology, 121881, https://doi.org/10.1016/j.chemgeo.2023.121881, 2023.
  • Grossman, E. L. and Ku, T.-L.: Oxygen and carbon isotope fractionation in biogenic aragonite: temperature effects, Chemical Geology: Isotope Geoscience section, 59, 59–74, 1986.
  • Gonfiantini, R., Stichler, W., and Rozanski, K.: Standards and intercomparison materials distributed by the International Atomic Energy Agency for stable isotope measurements, 1995.
  • Dettman, D. L., Reische, A. K., and Lohmann, K. C.: Controls on the stable isotope composition of seasonal growth bands in aragonitic fresh-water bivalves (Unionidae), Geochimica et Cosmochimica Acta, 63, 1049–1057, 1999.

Load packages¶

In [1]:
# Load packages
import numpy as np # The 'numpy' package is needed for matrix operations and calculations
import pandas as pd # The 'pandas' package helps us to import and manage data
import math as math # Math package for data cleaning
from scipy import stats # Import scipy.package for confidence intervals
from sklearn.preprocessing import StandardScaler # Import the package for standardizing data
import D47calib as D47c # Import the package for treating clumped isotope data by Daëron and Vermeesch (2023; https://github.com/mdaeron/D47calib)
import matplotlib.pyplot as plt # The 'matplotlib' package contains tools needed to plot our data and results
from matplotlib.patches import Rectangle # The 'Rectangle' function is used to add rectangles to our plots
import seaborn as sns # The 'seaborn' package is used to make our plots look nicer (e.g. enable heatmaps)
import warnings # The 'warnings' package is used to suppress warnings that might occur during the calculations
%matplotlib inline

PRIOR - MONTHLY¶

Load monthly SAT model data¶

In [2]:
# Load model SAT data as prior and show data structure
Lutetian_CESM_4PIC_SAT = pd.read_csv('Lutetian case/CESM_4PIC_SAT_Individual_values.csv') # Load the data from CESM model with 4x pre-industrial CO2 into Python and in the Jupyter environment.
print("CESM model 4PIC: ", Lutetian_CESM_4PIC_SAT.head())
Lutetian_CESM_2PIC_SAT = pd.read_csv('Lutetian case/CESM_2PIC_SAT_Individual_values.csv') # Load the data from CESM model with 2x pre-industrial CO2 into Python and in the Jupyter environment.
print("CESM model 2PIC: ", Lutetian_CESM_2PIC_SAT.head())
Lutetian_HadCM_new_1PIC_SAT = pd.read_csv('Lutetian case/HadCM_1PIC_SAT_new.csv') # Load the data from HadCM model with 1x pre-industrial CO2 into Python and in the Jupyter environment.
print("HadCM model 1PIC: ", Lutetian_HadCM_new_1PIC_SAT.head())
Lutetian_HadCM_new_2PIC_SAT = pd.read_csv('Lutetian case/HadCM_2PIC_SAT_new.csv') # Load the data from HadCM model with 2x pre-industrial CO2 into Python and in the Jupyter environment.
print("HadCM model 2PIC: ", Lutetian_HadCM_new_2PIC_SAT.head())
Lutetian_HadCM_new_1056ppm_SAT = pd.read_csv('Lutetian case/HadCM_1056ppm_SAT_new.csv') # Load the data from HadCM model with 1056ppm CO2 into Python and in the Jupyter environment.
print("HadCM model 1056ppm: ", Lutetian_HadCM_new_1056ppm_SAT.head())
Lutetian_HadCM_old_2PIC_SAT = pd.read_csv('Lutetian case/HadCM_2PIC_SAT_old.csv') # Load the data from HadCM model with 2x pre-industrial CO2 into Python and in the Jupyter environment.
print("HadCM model 2PIC (old): ", Lutetian_HadCM_old_2PIC_SAT.head())
Lutetian_HadCM_old_4PIC_SAT = pd.read_csv('Lutetian case/HadCM_4PIC_SAT_old.csv') # Load the data from HadCM model with 4x pre-industrial CO2 into Python and in the Jupyter environment.
print("HadCM model 4PIC (old): ", Lutetian_HadCM_old_4PIC_SAT.head())
CESM model 4PIC:     Month  Temperature
0      1    11.282648
1      1    21.823206
2      1    21.909296
3      1    22.503198
4      1    21.393762
CESM model 2PIC:     Month  Temperature
0      1     8.079706
1      1    18.723108
2      1    18.902612
3      1    19.552850
4      1    18.329370
HadCM model 1PIC:     Month        SAT
0      1   8.052789
1      1   5.543665
2      1   5.441797
3      1  11.657343
4      1   3.336206
HadCM model 2PIC:     Month        SAT
0      1  12.032495
1      1  10.032343
2      1  10.042474
3      1  15.231805
4      1   7.854364
HadCM model 1056ppm:     Month        SAT
0      1  14.752985
1      1  12.996912
2      1  13.127679
3      1  17.809625
4      1  11.005304
HadCM model 2PIC (old):     Month        SAT
0      1  16.109460
1      1  14.491327
2      1  14.220056
3      1  18.878229
4      1  10.043237
HadCM model 4PIC (old):     Month        SAT
0      1  16.109460
1      1  14.491327
2      1  14.220056
3      1  18.878229
4      1  10.043237

Load monthly SST model data¶

In [3]:
# Load model SST data as prior and show data structure
Lutetian_CESM_4PIC_SST = pd.read_csv('Lutetian case/CESM_4PIC_SST_Individual_values.csv') # Load the data from CESM model with 4x pre-industrial CO2 into Python and in the Jupyter environment.
print("CESM model 4PIC: ", Lutetian_CESM_4PIC_SST.head())
Lutetian_CESM_2PIC_SST = pd.read_csv('Lutetian case/CESM_2PIC_SST_Individual_values.csv') # Load the data from CESM model with 2x pre-industrial CO2 into Python and in the Jupyter environment.
print("CESM model 2PIC: ", Lutetian_CESM_2PIC_SST.head())
Lutetian_HadCM_new_1PIC_SST = pd.read_csv('Lutetian case/HadCM_1PIC_SST_new.csv') # Load the data from HadCM model with 1x pre-industrial CO2 into Python and in the Jupyter environment.
print("HadCM model 1PIC: ", Lutetian_HadCM_new_1PIC_SST.head())
Lutetian_HadCM_new_2PIC_SST = pd.read_csv('Lutetian case/HadCM_2PIC_SST_new.csv') # Load the data from HadCM model with 2x pre-industrial CO2 into Python and in the Jupyter environment.
print("HadCM model 2PIC: ", Lutetian_HadCM_new_2PIC_SST.head())
Lutetian_HadCM_new_1056ppm_SST = pd.read_csv('Lutetian case/HadCM_1056ppm_SST_new.csv') # Load the data from HadCM model with 1056ppm CO2 into Python and in the Jupyter environment.
print("HadCM model 1056ppm: ", Lutetian_HadCM_new_1056ppm_SST.head())
Lutetian_HadCM_old_2PIC_SST = pd.read_csv('Lutetian case/HadCM_2PIC_SST_old.csv') # Load the data from HadCM model with 2x pre-industrial CO2 into Python and in the Jupyter environment.
print("HadCM model 2PIC (old): ", Lutetian_HadCM_old_2PIC_SST.head())
Lutetian_HadCM_old_4PIC_SST = pd.read_csv('Lutetian case/HadCM_4PIC_SST_old.csv') # Load the data from HadCM model with 4x pre-industrial CO2 into Python and in the Jupyter environment.
print("HadCM model 4PIC (old): ", Lutetian_HadCM_old_4PIC_SST.head())
CESM model 4PIC:     Month        SST
0      1  25.653111
1      1  25.308791
2      1  24.928478
3      1  18.123590
4      1  18.129648
CESM model 2PIC:     Month        SST
0      1  22.904200
1      1  22.584154
2      1  22.211651
3      1  14.667439
4      1  14.675111
HadCM model 1PIC:     Month        SST
0      1  17.121233
1      1  17.339096
2      1  15.036237
3      1  17.758467
4      1  16.707846
HadCM model 2PIC:     Month        SST
0      1  19.588043
1      1  19.876625
2      1  17.857376
3      1  20.270193
4      1  19.358486
HadCM model 1056ppm:     Month        SST
0      1  21.546501
1      1  21.834936
2      1  19.857330
3      1  22.318356
4      1  21.426821
HadCM model 2PIC (old):     Month        SST
0      1  22.036110
1      1  21.993841
2      1  21.271461
3      1  21.397297
4      1  20.712231
HadCM model 4PIC (old):     Month        SST
0      1  22.036110
1      1  21.993841
2      1  21.271461
3      1  21.397297
4      1  20.712231

Load monthly SSS model data¶

In [4]:
# Load model SSS data as prior and show data structure
Lutetian_CESM_4PIC_SSS = pd.read_csv('Lutetian case/CESM_4PIC_SSS_Individual_values.csv') # Load the data from CESM model with 4x pre-industrial CO2 into Python and in the Jupyter environment.
print("CESM model 4PIC: ", Lutetian_CESM_4PIC_SSS.head())
Lutetian_CESM_2PIC_SSS = pd.read_csv('Lutetian case/CESM_2PIC_SSS_Individual_values.csv') # Load the data from CESM model with 2x pre-industrial CO2 into Python and in the Jupyter environment.
print("CESM model 2PIC: ", Lutetian_CESM_2PIC_SSS.head())
Lutetian_HadCM_new_1PIC_SSS = pd.read_csv('Lutetian case/HadCM_1PIC_SSS_new.csv') # Load the data from HadCM model with 1x pre-industrial CO2 into Python and in the Jupyter environment.
print("HadCM model 1PIC: ", Lutetian_HadCM_new_1PIC_SSS.head())
Lutetian_HadCM_new_2PIC_SSS = pd.read_csv('Lutetian case/HadCM_2PIC_SSS_new.csv') # Load the data from HadCM model with 2x pre-industrial CO2 into Python and in the Jupyter environment.
print("HadCM model 2PIC: ", Lutetian_HadCM_new_2PIC_SSS.head())
Lutetian_HadCM_new_1056ppm_SSS = pd.read_csv('Lutetian case/HadCM_1056ppm_SSS_new.csv') # Load the data from HadCM model with 1056ppm CO2 into Python and in the Jupyter environment.
print("HadCM model 1056ppm: ", Lutetian_HadCM_new_1056ppm_SSS.head())
Lutetian_HadCM_old_2PIC_SSS = pd.read_csv('Lutetian case/HadCM_2PIC_SSS_old.csv') # Load the data from HadCM model with 2x pre-industrial CO2 into Python and in the Jupyter environment.
print("HadCM model 2PIC (old): ", Lutetian_HadCM_old_2PIC_SSS.head())
Lutetian_HadCM_old_4PIC_SSS = pd.read_csv('Lutetian case/HadCM_4PIC_SSS_old.csv') # Load the data from HadCM model with 4x pre-industrial CO2 into Python and in the Jupyter environment.
print("HadCM model 4PIC (old): ", Lutetian_HadCM_old_4PIC_SSS.head())
CESM model 4PIC:     Month        SSS
0      1  35.445849
1      1  35.447266
2      1  35.370330
3      1  27.677744
4      1  27.647815
CESM model 2PIC:     Month        SSS
0      1  35.611739
1      1  35.605736
2      1  35.525519
3      1  28.101734
4      1  28.084953
HadCM model 1PIC:     Month        SSS
0      1  36.600336
1      1  36.589958
2      1  36.418869
3      1  36.613618
4      1  36.546343
HadCM model 2PIC:     Month        SSS
0      1  36.903056
1      1  36.886427
2      1  36.710143
3      1  36.917722
4      1  36.842750
HadCM model 1056ppm:     Month        SSS
0      1  37.131014
1      1  37.101769
2      1  36.907516
3      1  37.167668
4      1  37.071734
HadCM model 2PIC (old):     Month        SSS
0      1  43.906515
1      1  44.145954
2      1  44.298574
3      1  44.078606
4      1  44.195226
HadCM model 4PIC (old):     Month        SSS
0      1  43.906515
1      1  44.145954
2      1  44.298574
3      1  44.078606
4      1  44.195226

Load monthly precipitation model data¶

In [5]:
# Load model precipitation data as prior and show data structure
Lutetian_CESM_4PIC_prec = pd.read_csv('Lutetian case/CESM_4PIC_Precipitation_Individual_values.csv') # Load the data from CESM model with 4x pre-industrial CO2 into Python and in the Jupyter environment.
print("CESM model 4PIC: ", Lutetian_CESM_4PIC_prec.head())
Lutetian_CESM_2PIC_prec = pd.read_csv('Lutetian case/CESM_2PIC_Precipitation_Individual_values.csv') # Load the data from CESM model with 2x pre-industrial CO2 into Python and in the Jupyter environment.
print("CESM model 2PIC: ", Lutetian_CESM_2PIC_prec.head())
Lutetian_HadCM_new_1PIC_prec = pd.read_csv('Lutetian case/HadCM_1PIC_Precipitation_new.csv') # Load the data from HadCM model with 1x pre-industrial CO2 into Python and in the Jupyter environment.
print("HadCM model 1PIC: ", Lutetian_HadCM_new_1PIC_prec.head())
Lutetian_HadCM_new_2PIC_prec = pd.read_csv('Lutetian case/HadCM_2PIC_Precipitation_new.csv') # Load the data from HadCM model with 2x pre-industrial CO2 into Python and in the Jupyter environment.
print("HadCM model 2PIC: ", Lutetian_HadCM_new_2PIC_prec.head())
Lutetian_HadCM_new_1056ppm_prec = pd.read_csv('Lutetian case/HadCM_1056ppm_Precipitation_new.csv') # Load the data from HadCM model with 1056ppm CO2 into Python and in the Jupyter environment.
print("HadCM model 1056ppm: ", Lutetian_HadCM_new_1056ppm_prec.head())
Lutetian_HadCM_old_2PIC_prec = pd.read_csv('Lutetian case/HadCM_2PIC_Precipitation_old.csv') # Load the data from HadCM model with 2x pre-industrial CO2 into Python and in the Jupyter environment.
print("HadCM model 2PIC (old): ", Lutetian_HadCM_old_2PIC_prec.head())
Lutetian_HadCM_old_4PIC_prec = pd.read_csv('Lutetian case/HadCM_4PIC_Precipitation_old.csv') # Load the data from HadCM model with 4x pre-industrial CO2 into Python and in the Jupyter environment.
print("HadCM model 4PIC (old): ", Lutetian_HadCM_old_4PIC_prec.head())
CESM model 4PIC:     Month  Precipitation
0      1       3.528070
1      1       1.148649
2      1       2.255904
3      1       2.247083
4      1       2.146144
CESM model 2PIC:     Month  Precipitation
0      1       4.098786
1      1       1.263385
2      1       2.206109
3      1       2.211890
4      1       2.020240
HadCM model 1PIC:     Month  Precipitation
0      1       2.406142
1      1       1.957261
2      1       3.106018
3      1       2.795490
4      1       2.562401
HadCM model 2PIC:     Month  Precipitation
0      1       3.428225
1      1       2.581973
2      1       3.858653
3      1       3.660850
4      1       3.468367
HadCM model 1056ppm:     Month  Precipitation
0      1       4.779313
1      1       3.294503
2      1       4.737308
3      1       4.740917
4      1       4.566842
HadCM model 2PIC (old):     Month  Precipitation
0      1       5.331755
1      1       3.825469
2      1       5.138381
3      1       4.515986
4      1       4.612467
HadCM model 4PIC (old):     Month  Precipitation
0      1       5.331755
1      1       3.825469
2      1       5.138381
3      1       4.515986
4      1       4.612467

Combine climate data by modelname¶

For CESM with 4x preindustrial pCO2¶

In [6]:
# For CESM model with 4x pre-industrial CO2, combine the datasets of SAT, SST, SSS and prec into one dataset for further analysis

# Add a column to number the rows within each month consecutively
Lutetian_CESM_4PIC_SAT['Cell'] = Lutetian_CESM_4PIC_SAT.groupby('Month').cumcount() + 1
Lutetian_CESM_4PIC_SST['Cell'] = Lutetian_CESM_4PIC_SST.groupby('Month').cumcount() + 1
Lutetian_CESM_4PIC_SSS['Cell'] = Lutetian_CESM_4PIC_SSS.groupby('Month').cumcount() + 1
Lutetian_CESM_4PIC_prec['Cell'] = Lutetian_CESM_4PIC_prec.groupby('Month').cumcount() + 1

# Pivot the datasets to create separate columns for each month with 2-letter abbreviations
month_abbreviations = ['ja', 'fb', 'mr', 'ar', 'my', 'jn', 'jl', 'ag', 'sp', 'ot', 'nv', 'dc']
Lutetian_CESM_4PIC_SAT_wide = Lutetian_CESM_4PIC_SAT.pivot(index='Cell', columns='Month', values='Temperature')
Lutetian_CESM_4PIC_SAT_wide.columns = [month_abbreviations[col - 1] for col in Lutetian_CESM_4PIC_SAT_wide.columns]
Lutetian_CESM_4PIC_SST_wide = Lutetian_CESM_4PIC_SST.pivot(index='Cell', columns='Month', values='SST')
Lutetian_CESM_4PIC_SST_wide.columns = [month_abbreviations[col - 1] for col in Lutetian_CESM_4PIC_SST_wide.columns]
Lutetian_CESM_4PIC_SSS_wide = Lutetian_CESM_4PIC_SSS.pivot(index='Cell', columns='Month', values='SSS')
Lutetian_CESM_4PIC_SSS_wide.columns = [month_abbreviations[col - 1] for col in Lutetian_CESM_4PIC_SSS_wide.columns]
Lutetian_CESM_4PIC_prec_wide = Lutetian_CESM_4PIC_prec.pivot(index='Cell', columns='Month', values='Precipitation')
Lutetian_CESM_4PIC_prec_wide.columns = [month_abbreviations[col - 1] for col in Lutetian_CESM_4PIC_prec_wide.columns]

# Reset the index to make 'Cell' a column again
Lutetian_CESM_4PIC_SAT_wide.reset_index(inplace = True)
Lutetian_CESM_4PIC_SST_wide.reset_index(inplace = True)
Lutetian_CESM_4PIC_SSS_wide.reset_index(inplace = True)
Lutetian_CESM_4PIC_prec_wide.reset_index(inplace = True)

# Merge the datasets of SAT, SST, SSS and prec, force suffixes to be added to the column names
# Merge in two steps to circumvent different numbers of cells due to differing spatial resolution in air and ocean models
Lutetian_CESM_4PIC_model = pd.merge(
    # Merge SAT and prec data
    pd.merge(
        Lutetian_CESM_4PIC_SAT_wide.rename(columns = {c: c+'_SAT' for c in Lutetian_CESM_4PIC_SAT_wide.columns if c != 'Cell'}),
        Lutetian_CESM_4PIC_prec_wide.rename(columns = {c: c+'_precip' for c in Lutetian_CESM_4PIC_prec_wide.columns if c != 'Cell'}),
        on = 'Cell',
        how = 'outer'
    ),
    # Merge SST and SSS data
    pd.merge(
        Lutetian_CESM_4PIC_SST_wide.rename(columns = {c: c+'_SST' for c in Lutetian_CESM_4PIC_SST_wide.columns if c != 'Cell'}),
        Lutetian_CESM_4PIC_SSS_wide.rename(columns = {c: c+'_SSS' for c in Lutetian_CESM_4PIC_SSS_wide.columns if c != 'Cell'}),
        on = 'Cell',
        how = 'outer'
    ),
    on = 'Cell',
    how = 'outer'
)

# Display the combined dataset
print("CESM 4x pre-industrial CO2 combined dataset:")
print(Lutetian_CESM_4PIC_model.head())
CESM 4x pre-industrial CO2 combined dataset:
   Cell     ja_SAT     fb_SAT     mr_SAT     ar_SAT     my_SAT     jn_SAT  \
0     1  11.282648  12.089380  13.829187  16.709039  22.411493  27.940820   
1     2  21.823206  22.185327  23.480707  25.735864  30.242242  35.107660   
2     3  21.909296  22.198022  23.222040  25.234583  29.434015  34.056543   
3     4  22.503198  22.530481  23.346246  25.152704  28.970605  33.480951   
4     5  21.393762  21.576868  22.996118  25.669275  30.826440  36.038263   

      jl_SAT     ag_SAT     sp_SAT  ...     mr_SSS     ar_SSS     my_SSS  \
0  30.968195  31.072290  26.694391  ...  35.461410  35.476315  35.502321   
1  38.680688  39.036523  35.629755  ...  35.474837  35.491815  35.518168   
2  38.089227  38.691492  35.554956  ...  35.391840  35.407201  35.434341   
3  37.780298  38.492792  35.470605  ...  27.740462  27.669306  27.565980   
4  40.872888  40.882013  36.701257  ...  27.695703  27.609018  27.476092   

      jn_SSS     jl_SSS     ag_SSS     sp_SSS     ot_SSS     nv_SSS     dc_SSS  
0  35.524816  35.519439  35.469567  35.353144  35.262145  35.298730  35.386242  
1  35.535836  35.529558  35.499538  35.409034  35.322384  35.326226  35.393769  
2  35.446876  35.436236  35.413111  35.338840  35.276135  35.276722  35.330491  
3  27.477787  27.376960  27.298817  27.239179  27.249114  27.380852  27.560293  
4  27.362065  27.253544  27.175085  27.119611  27.145849  27.320097  27.518127  

[5 rows x 49 columns]

For CESM with 2x preindustrial pCO2¶

In [7]:
# For CESM model with 2x pre-industrial CO2, combine the datasets of SAT, SST, SSS and prec into one dataset for further analysis

# Add a column to number the rows within each month consecutively
Lutetian_CESM_2PIC_SAT['Cell'] = Lutetian_CESM_2PIC_SAT.groupby('Month').cumcount() + 1
Lutetian_CESM_2PIC_SST['Cell'] = Lutetian_CESM_2PIC_SST.groupby('Month').cumcount() + 1
Lutetian_CESM_2PIC_SSS['Cell'] = Lutetian_CESM_2PIC_SSS.groupby('Month').cumcount() + 1
Lutetian_CESM_2PIC_prec['Cell'] = Lutetian_CESM_2PIC_prec.groupby('Month').cumcount() + 1

# Pivot the datasets to create separate columns for each month with 2-letter abbreviations
Lutetian_CESM_2PIC_SAT_wide = Lutetian_CESM_2PIC_SAT.pivot(index='Cell', columns='Month', values='Temperature')
Lutetian_CESM_2PIC_SAT_wide.columns = [month_abbreviations[col - 1] for col in Lutetian_CESM_2PIC_SAT_wide.columns]
Lutetian_CESM_2PIC_SST_wide = Lutetian_CESM_2PIC_SST.pivot(index='Cell', columns='Month', values='SST')
Lutetian_CESM_2PIC_SST_wide.columns = [month_abbreviations[col - 1] for col in Lutetian_CESM_2PIC_SST_wide.columns]
Lutetian_CESM_2PIC_SSS_wide = Lutetian_CESM_2PIC_SSS.pivot(index='Cell', columns='Month', values='SSS')
Lutetian_CESM_2PIC_SSS_wide.columns = [month_abbreviations[col - 1] for col in Lutetian_CESM_2PIC_SSS_wide.columns]
Lutetian_CESM_2PIC_prec_wide = Lutetian_CESM_2PIC_prec.pivot(index='Cell', columns='Month', values='Precipitation')
Lutetian_CESM_2PIC_prec_wide.columns = [month_abbreviations[col - 1] for col in Lutetian_CESM_2PIC_prec_wide.columns]

# Reset the index to make 'Cell' a column again
Lutetian_CESM_2PIC_SAT_wide.reset_index(inplace = True)
Lutetian_CESM_2PIC_SST_wide.reset_index(inplace = True)
Lutetian_CESM_2PIC_SSS_wide.reset_index(inplace = True)
Lutetian_CESM_2PIC_prec_wide.reset_index(inplace = True)

# Merge the datasets of SAT, SST, SSS and prec, force suffixes to be added to the column names
# Merge in two steps to circumvent different numbers of cells due to differing spatial resolution in air and ocean models
Lutetian_CESM_2PIC_model = pd.merge(
    # Merge SAT and prec data
    pd.merge(
        Lutetian_CESM_2PIC_SAT_wide.rename(columns = {c: c+'_SAT' for c in Lutetian_CESM_2PIC_SAT_wide.columns if c != 'Cell'}),
        Lutetian_CESM_2PIC_prec_wide.rename(columns = {c: c+'_precip' for c in Lutetian_CESM_2PIC_prec_wide.columns if c != 'Cell'}),
        on = 'Cell',
        how = 'outer'
    ),
    # Merge SST and SSS data
    pd.merge(
        Lutetian_CESM_2PIC_SST_wide.rename(columns = {c: c+'_SST' for c in Lutetian_CESM_2PIC_SST_wide.columns if c != 'Cell'}),
        Lutetian_CESM_2PIC_SSS_wide.rename(columns = {c: c+'_SSS' for c in Lutetian_CESM_2PIC_SSS_wide.columns if c != 'Cell'}),
        on = 'Cell',
        how = 'outer'
    ),
    on = 'Cell',
    how = 'outer'
)

# Display the combined dataset
print("CESM 2x pre-industrial CO2 combined dataset:")
print(Lutetian_CESM_2PIC_model.head())
CESM 2x pre-industrial CO2 combined dataset:
   Cell     ja_SAT     fb_SAT     mr_SAT     ar_SAT     my_SAT     jn_SAT  \
0     1   8.079706   8.682245  10.292291  13.623804  18.543329  22.827844   
1     2  18.723108  19.036798  20.318903  22.775720  26.905450  31.019128   
2     3  18.902612  19.163934  20.205408  22.355096  26.210016  30.252496   
3     4  19.552850  19.557764  20.425623  22.352350  25.905756  29.882379   
4     5  18.329370  18.452631  19.794916  22.507562  27.185938  31.563654   

      jl_SAT     ag_SAT     sp_SAT  ...     mr_SSS     ar_SSS     my_SSS  \
0  25.661005  25.911890  22.544611  ...  35.557816  35.549113  35.578386   
1  34.275934  34.816797  31.946375  ...  35.568414  35.559291  35.579439   
2  34.047083  34.686151  32.002588  ...  35.488143  35.475190  35.489032   
3  33.956262  34.617273  31.891870  ...  28.127362  28.017930  27.871013   
4  36.184412  36.466760  32.711786  ...  28.087784  27.952144  27.782063   

      jn_SSS     jl_SSS     ag_SSS     sp_SSS     ot_SSS     nv_SSS     dc_SSS  
0  35.604078  35.612619  35.590057  35.542811  35.520497  35.563135  35.608150  
1  35.598084  35.603424  35.595446  35.571139  35.549517  35.570238  35.601316  
2  35.499420  35.495488  35.490418  35.487392  35.482942  35.506846  35.529809  
3  27.769361  27.677441  27.601284  27.565443  27.592602  27.742316  27.963268  
4  27.661411  27.563237  27.489528  27.457962  27.502879  27.701501  27.951535  

[5 rows x 49 columns]

For HadCM with 1x preindustrial pCO2 (new model)¶

In [8]:
# For HadCM model with 1x pre-industrial CO2, combine the datasets of SAT, SST, SSS and prec into one dataset for further analysis

# Add a column to number the rows within each month consecutively
Lutetian_HadCM_new_1PIC_SAT['Cell'] = Lutetian_HadCM_new_1PIC_SAT.groupby('Month').cumcount() + 1
Lutetian_HadCM_new_1PIC_SST['Cell'] = Lutetian_HadCM_new_1PIC_SST.groupby('Month').cumcount() + 1
Lutetian_HadCM_new_1PIC_SSS['Cell'] = Lutetian_HadCM_new_1PIC_SSS.groupby('Month').cumcount() + 1
Lutetian_HadCM_new_1PIC_prec['Cell'] = Lutetian_HadCM_new_1PIC_prec.groupby('Month').cumcount() + 1

# Pivot the datasets to create separate columns for each month with 2-letter abbreviations
Lutetian_HadCM_new_1PIC_SAT_wide = Lutetian_HadCM_new_1PIC_SAT.pivot(index='Cell', columns='Month', values='SAT')
Lutetian_HadCM_new_1PIC_SAT_wide.columns = [month_abbreviations[col - 1] for col in Lutetian_HadCM_new_1PIC_SAT_wide.columns]
Lutetian_HadCM_new_1PIC_SST_wide = Lutetian_HadCM_new_1PIC_SST.pivot(index='Cell', columns='Month', values='SST')
Lutetian_HadCM_new_1PIC_SST_wide.columns = [month_abbreviations[col - 1] for col in Lutetian_HadCM_new_1PIC_SST_wide.columns]
Lutetian_HadCM_new_1PIC_SSS_wide = Lutetian_HadCM_new_1PIC_SSS.pivot(index='Cell', columns='Month', values='SSS')
Lutetian_HadCM_new_1PIC_SSS_wide.columns = [month_abbreviations[col - 1] for col in Lutetian_HadCM_new_1PIC_SSS_wide.columns]
Lutetian_HadCM_new_1PIC_prec_wide = Lutetian_HadCM_new_1PIC_prec.pivot(index='Cell', columns='Month', values='Precipitation')
Lutetian_HadCM_new_1PIC_prec_wide.columns = [month_abbreviations[col - 1] for col in Lutetian_HadCM_new_1PIC_prec_wide.columns]

# Reset the index to make 'Cell' a column again
Lutetian_HadCM_new_1PIC_SAT_wide.reset_index(inplace = True)
Lutetian_HadCM_new_1PIC_SST_wide.reset_index(inplace = True)
Lutetian_HadCM_new_1PIC_SSS_wide.reset_index(inplace = True)
Lutetian_HadCM_new_1PIC_prec_wide.reset_index(inplace = True)

# Merge the datasets of SAT, SST, SSS and prec, force suffixes to be added to the column names
# Merge in two steps to circumvent different numbers of cells due to differing spatial resolution in air and ocean models
Lutetian_HadCM_new_1PIC_model = pd.merge(
    # Merge SAT and prec data
    pd.merge(
        Lutetian_HadCM_new_1PIC_SAT_wide.rename(columns = {c: c+'_SAT' for c in Lutetian_HadCM_new_1PIC_SAT_wide.columns if c != 'Cell'}),
        Lutetian_HadCM_new_1PIC_prec_wide.rename(columns = {c: c+'_precip' for c in Lutetian_HadCM_new_1PIC_prec_wide.columns if c != 'Cell'}),
        on = 'Cell',
        how = 'outer'
    ),
    # Merge SST and SSS data
    pd.merge(
        Lutetian_HadCM_new_1PIC_SST_wide.rename(columns = {c: c+'_SST' for c in Lutetian_HadCM_new_1PIC_SST_wide.columns if c != 'Cell'}),
        Lutetian_HadCM_new_1PIC_SSS_wide.rename(columns = {c: c+'_SSS' for c in Lutetian_HadCM_new_1PIC_SSS_wide.columns if c != 'Cell'}),
        on = 'Cell',
        how = 'outer'
    ),
    on = 'Cell',
    how = 'outer'
)

# Display the combined dataset
print("HadCM 1x pre-industrial CO2 combined dataset:")
print(Lutetian_HadCM_new_1PIC_model.head())
HadCM 1x pre-industrial CO2 combined dataset:
   Cell     ja_SAT     fb_SAT     mr_SAT     ar_SAT     my_SAT     jn_SAT  \
0     1   8.052789   7.992517   8.733209  10.359064  13.972986  19.524438   
1     2   5.543665   5.446466   6.303369   8.327386  12.788965  18.906274   
2     3   5.441797   5.020135   5.603723   7.323083  11.379724  17.331293   
3     4  11.657343  11.682520  12.354303  13.548639  16.459161  21.680658   
4     5   3.336206   5.344659   8.210504  11.033441  15.833429  20.868097   

      jl_SAT     ag_SAT     sp_SAT  ...     mr_SSS     ar_SSS     my_SSS  \
0  24.154474  25.112024  22.214838  ...  36.579043  36.582041  36.582377   
1  23.355554  24.378473  21.271326  ...  36.590740  36.600344  36.610681   
2  22.398523  23.914362  21.047418  ...  36.406383  36.429290  36.462274   
3  25.439905  26.119257  24.086908  ...  36.593636  36.589672  36.575392   
4  23.159937  23.440515  20.537500  ...  36.549568  36.556936  36.568931   

      jn_SSS     jl_SSS     ag_SSS     sp_SSS     ot_SSS     nv_SSS     dc_SSS  
0  36.562211  36.522156  36.497449  36.542234  36.608670  36.635368  36.626951  
1  36.615911  36.585364  36.565986  36.597584  36.633123  36.636892  36.619583  
2  36.489640  36.471493  36.454039  36.492532  36.519571  36.500253  36.461642  
3  36.536135  36.464259  36.407722  36.455007  36.527968  36.575614  36.601006  
4  36.551240  36.519668  36.495510  36.528441  36.575906  36.555548  36.545291  

[5 rows x 49 columns]

For HadCM with 2x preindustrial pCO2 (new model)¶

In [9]:
# For HadCM model with 2x pre-industrial CO2, combine the datasets of SAT, SST, SSS and prec into one dataset for further analysis

# Add a column to number the rows within each month consecutively
Lutetian_HadCM_new_2PIC_SAT['Cell'] = Lutetian_HadCM_new_2PIC_SAT.groupby('Month').cumcount() + 1
Lutetian_HadCM_new_2PIC_SST['Cell'] = Lutetian_HadCM_new_2PIC_SST.groupby('Month').cumcount() + 1
Lutetian_HadCM_new_2PIC_SSS['Cell'] = Lutetian_HadCM_new_2PIC_SSS.groupby('Month').cumcount() + 1
Lutetian_HadCM_new_2PIC_prec['Cell'] = Lutetian_HadCM_new_2PIC_prec.groupby('Month').cumcount() + 1

# Pivot the datasets to create separate columns for each month with 2-letter abbreviations
Lutetian_HadCM_new_2PIC_SAT_wide = Lutetian_HadCM_new_2PIC_SAT.pivot(index='Cell', columns='Month', values='SAT')
Lutetian_HadCM_new_2PIC_SAT_wide.columns = [month_abbreviations[col - 1] for col in Lutetian_HadCM_new_2PIC_SAT_wide.columns]
Lutetian_HadCM_new_2PIC_SST_wide = Lutetian_HadCM_new_2PIC_SST.pivot(index='Cell', columns='Month', values='SST')
Lutetian_HadCM_new_2PIC_SST_wide.columns = [month_abbreviations[col - 1] for col in Lutetian_HadCM_new_2PIC_SST_wide.columns]
Lutetian_HadCM_new_2PIC_SSS_wide = Lutetian_HadCM_new_2PIC_SSS.pivot(index='Cell', columns='Month', values='SSS')
Lutetian_HadCM_new_2PIC_SSS_wide.columns = [month_abbreviations[col - 1] for col in Lutetian_HadCM_new_2PIC_SSS_wide.columns]
Lutetian_HadCM_new_2PIC_prec_wide = Lutetian_HadCM_new_2PIC_prec.pivot(index='Cell', columns='Month', values='Precipitation')
Lutetian_HadCM_new_2PIC_prec_wide.columns = [month_abbreviations[col - 1] for col in Lutetian_HadCM_new_2PIC_prec_wide.columns]

# Reset the index to make 'Cell' a column again
Lutetian_HadCM_new_2PIC_SAT_wide.reset_index(inplace = True)
Lutetian_HadCM_new_2PIC_SST_wide.reset_index(inplace = True)
Lutetian_HadCM_new_2PIC_SSS_wide.reset_index(inplace = True)
Lutetian_HadCM_new_2PIC_prec_wide.reset_index(inplace = True)

# Merge the datasets of SAT, SST, SSS and prec, force suffixes to be added to the column names
# Merge in two steps to circumvent different numbers of cells due to differing spatial resolution in air and ocean models
Lutetian_HadCM_new_2PIC_model = pd.merge(
    # Merge SAT and prec data
    pd.merge(
        Lutetian_HadCM_new_2PIC_SAT_wide.rename(columns = {c: c+'_SAT' for c in Lutetian_HadCM_new_2PIC_SAT_wide.columns if c != 'Cell'}),
        Lutetian_HadCM_new_2PIC_prec_wide.rename(columns = {c: c+'_precip' for c in Lutetian_HadCM_new_2PIC_prec_wide.columns if c != 'Cell'}),
        on = 'Cell',
        how = 'outer'
    ),
    # Merge SST and SSS data
    pd.merge(
        Lutetian_HadCM_new_2PIC_SST_wide.rename(columns = {c: c+'_SST' for c in Lutetian_HadCM_new_2PIC_SST_wide.columns if c != 'Cell'}),
        Lutetian_HadCM_new_2PIC_SSS_wide.rename(columns = {c: c+'_SSS' for c in Lutetian_HadCM_new_2PIC_SSS_wide.columns if c != 'Cell'}),
        on = 'Cell',
        how = 'outer'
    ),
    on = 'Cell',
    how = 'outer'
)

# Display the combined dataset
print("HadCM 2x pre-industrial CO2 combined dataset:")
print(Lutetian_HadCM_new_2PIC_model.head())
HadCM 2x pre-industrial CO2 combined dataset:
   Cell     ja_SAT     fb_SAT     mr_SAT     ar_SAT     my_SAT     jn_SAT  \
0     1  12.032495  11.765405  12.540948  14.017786  17.638818  22.951166   
1     2  10.032343   9.614069  10.567499  12.368372  16.857782  23.125818   
2     3  10.042474   9.279749   9.883508  11.388208  15.628229  21.994348   
3     4  15.231805  14.956903  15.680139  16.795190  19.790338  24.812463   
4     5   7.854364   8.944025  11.926355  14.481989  19.159235  24.058344   

      jl_SAT     ag_SAT     sp_SAT  ...     mr_SSS     ar_SSS     my_SSS  \
0  27.410181  28.291254  25.576105  ...  36.880476  36.889930  36.874808   
1  27.034113  27.580316  24.560754  ...  36.887639  36.901384  36.904206   
2  26.338739  27.108881  24.157251  ...  36.695585  36.722629  36.756006   
3  28.288263  28.865594  26.970605  ...  36.891104  36.888574  36.860925   
4  26.157434  26.275842  23.426965  ...  36.842747  36.854991  36.855491   

      jn_SSS     jl_SSS     ag_SSS     sp_SSS     ot_SSS     nv_SSS     dc_SSS  
0  36.864941  36.848321  36.827491  36.892424  36.946852  36.962674  36.939401  
1  36.921163  36.901155  36.878949  36.930710  36.959289  36.949357  36.918651  
2  36.786631  36.773049  36.764045  36.815244  36.832087  36.800560  36.756923  
3  36.831438  36.801560  36.726469  36.785466  36.852630  36.891959  36.908774  
4  36.838816  36.819720  36.786201  36.836641  36.885977  36.861411  36.844403  

[5 rows x 49 columns]

For HadCM with 1056 ppm pCO2 (new model)¶

In [10]:
# For HadCM model with 1056 ppm CO2, combine the datasets of SAT, SST, SSS and prec into one dataset for further analysis

# Add a column to number the rows within each month consecutively
Lutetian_HadCM_new_1056ppm_SAT['Cell'] = Lutetian_HadCM_new_1056ppm_SAT.groupby('Month').cumcount() + 1
Lutetian_HadCM_new_1056ppm_SST['Cell'] = Lutetian_HadCM_new_1056ppm_SST.groupby('Month').cumcount() + 1
Lutetian_HadCM_new_1056ppm_SSS['Cell'] = Lutetian_HadCM_new_1056ppm_SSS.groupby('Month').cumcount() + 1
Lutetian_HadCM_new_1056ppm_prec['Cell'] = Lutetian_HadCM_new_1056ppm_prec.groupby('Month').cumcount() + 1

# Pivot the datasets to create separate columns for each month with 2-letter abbreviations
Lutetian_HadCM_new_1056ppm_SAT_wide = Lutetian_HadCM_new_1056ppm_SAT.pivot(index='Cell', columns='Month', values='SAT')
Lutetian_HadCM_new_1056ppm_SAT_wide.columns = [month_abbreviations[col - 1] for col in Lutetian_HadCM_new_1056ppm_SAT_wide.columns]
Lutetian_HadCM_new_1056ppm_SST_wide = Lutetian_HadCM_new_1056ppm_SST.pivot(index='Cell', columns='Month', values='SST')
Lutetian_HadCM_new_1056ppm_SST_wide.columns = [month_abbreviations[col - 1] for col in Lutetian_HadCM_new_1056ppm_SST_wide.columns]
Lutetian_HadCM_new_1056ppm_SSS_wide = Lutetian_HadCM_new_1056ppm_SSS.pivot(index='Cell', columns='Month', values='SSS')
Lutetian_HadCM_new_1056ppm_SSS_wide.columns = [month_abbreviations[col - 1] for col in Lutetian_HadCM_new_1056ppm_SSS_wide.columns]
Lutetian_HadCM_new_1056ppm_prec_wide = Lutetian_HadCM_new_1056ppm_prec.pivot(index='Cell', columns='Month', values='Precipitation')
Lutetian_HadCM_new_1056ppm_prec_wide.columns = [month_abbreviations[col - 1] for col in Lutetian_HadCM_new_1056ppm_prec_wide.columns]

# Reset the index to make 'Cell' a column again
Lutetian_HadCM_new_1056ppm_SAT_wide.reset_index(inplace = True)
Lutetian_HadCM_new_1056ppm_SST_wide.reset_index(inplace = True)
Lutetian_HadCM_new_1056ppm_SSS_wide.reset_index(inplace = True)
Lutetian_HadCM_new_1056ppm_prec_wide.reset_index(inplace = True)

# Merge the datasets of SAT, SST, SSS and prec, force suffixes to be added to the column names
# Merge in two steps to circumvent different numbers of cells due to differing spatial resolution in air and ocean models
Lutetian_HadCM_new_1056ppm_model = pd.merge(
    # Merge SAT and prec data
    pd.merge(
        Lutetian_HadCM_new_1056ppm_SAT_wide.rename(columns = {c: c+'_SAT' for c in Lutetian_HadCM_new_1056ppm_SAT_wide.columns if c != 'Cell'}),
        Lutetian_HadCM_new_1056ppm_prec_wide.rename(columns = {c: c+'_precip' for c in Lutetian_HadCM_new_1056ppm_prec_wide.columns if c != 'Cell'}),
        on = 'Cell',
        how = 'outer'
    ),
    # Merge SST and SSS data
    pd.merge(
        Lutetian_HadCM_new_1056ppm_SST_wide.rename(columns = {c: c+'_SST' for c in Lutetian_HadCM_new_1056ppm_SST_wide.columns if c != 'Cell'}),
        Lutetian_HadCM_new_1056ppm_SSS_wide.rename(columns = {c: c+'_SSS' for c in Lutetian_HadCM_new_1056ppm_SSS_wide.columns if c != 'Cell'}),
        on = 'Cell',
        how = 'outer'
    ),
    on = 'Cell',
    how = 'outer'
)

# Display the combined dataset
print("HadCM 1056 ppm CO2 combined dataset:")
print(Lutetian_HadCM_new_1056ppm_model.head())
HadCM 1056 ppm CO2 combined dataset:
   Cell     ja_SAT     fb_SAT     mr_SAT     ar_SAT     my_SAT     jn_SAT  \
0     1  14.752985  14.494897  14.980402  16.575220  20.000818  25.204980   
1     2  12.996912  12.753046  13.208704  15.260828  19.392999  25.608850   
2     3  13.127679  12.599512  12.679742  14.343317  18.218500  24.699243   
3     4  17.809625  17.621484  17.975031  19.288171  22.094263  26.878717   
4     5  11.005304  12.533258  14.417230  17.510217  21.609277  26.559656   

      jl_SAT     ag_SAT     sp_SAT  ...     mr_SSS     ar_SSS     my_SSS  \
0  29.662347  30.615137  28.027460  ...  37.107916  37.122627  37.129847   
1  29.630823  30.056573  27.234857  ...  37.100452  37.119542  37.140229   
2  28.905939  29.489587  26.775018  ...  36.894937  36.932385  36.979232   
3  30.409326  31.094934  29.279382  ...  37.126426  37.127387  37.107266   
4  29.221490  29.027551  26.355951  ...  37.061939  37.079618  37.092974   

      jn_SSS     jl_SSS     ag_SSS     sp_SSS     ot_SSS     nv_SSS     dc_SSS  
0  37.127376  37.156189  37.201068  37.261104  37.257688  37.229975  37.179673  
1  37.165682  37.184126  37.210042  37.259688  37.232547  37.185048  37.135684  
2  37.024214  37.038639  37.058643  37.104572  37.072104  37.012180  36.958759  
3  37.073434  37.093539  37.108810  37.146504  37.171028  37.184294  37.174637  
4  37.076982  37.090555  37.117251  37.161991  37.165776  37.111025  37.079348  

[5 rows x 49 columns]

For HadCM with 2x preindustrial pCO2 (old model)¶

In [11]:
# For old HadCM model with 2x pre-industrial CO2, combine the datasets of SAT, SST, SSS and prec into one dataset for further analysis

# Add a column to number the rows within each month consecutively
Lutetian_HadCM_old_2PIC_SAT['Cell'] = Lutetian_HadCM_old_2PIC_SAT.groupby('Month').cumcount() + 1
Lutetian_HadCM_old_2PIC_SST['Cell'] = Lutetian_HadCM_old_2PIC_SST.groupby('Month').cumcount() + 1
Lutetian_HadCM_old_2PIC_SSS['Cell'] = Lutetian_HadCM_old_2PIC_SSS.groupby('Month').cumcount() + 1
Lutetian_HadCM_old_2PIC_prec['Cell'] = Lutetian_HadCM_old_2PIC_prec.groupby('Month').cumcount() + 1

# Pivot the datasets to create separate columns for each month with 2-letter abbreviations
Lutetian_HadCM_old_2PIC_SAT_wide = Lutetian_HadCM_old_2PIC_SAT.pivot(index='Cell', columns='Month', values='SAT')
Lutetian_HadCM_old_2PIC_SAT_wide.columns = [month_abbreviations[col - 1] for col in Lutetian_HadCM_old_2PIC_SAT_wide.columns]
Lutetian_HadCM_old_2PIC_SST_wide = Lutetian_HadCM_old_2PIC_SST.pivot(index='Cell', columns='Month', values='SST')
Lutetian_HadCM_old_2PIC_SST_wide.columns = [month_abbreviations[col - 1] for col in Lutetian_HadCM_old_2PIC_SST_wide.columns]
Lutetian_HadCM_old_2PIC_SSS_wide = Lutetian_HadCM_old_2PIC_SSS.pivot(index='Cell', columns='Month', values='SSS')
Lutetian_HadCM_old_2PIC_SSS_wide.columns = [month_abbreviations[col - 1] for col in Lutetian_HadCM_old_2PIC_SSS_wide.columns]
Lutetian_HadCM_old_2PIC_prec_wide = Lutetian_HadCM_old_2PIC_prec.pivot(index='Cell', columns='Month', values='Precipitation')
Lutetian_HadCM_old_2PIC_prec_wide.columns = [month_abbreviations[col - 1] for col in Lutetian_HadCM_old_2PIC_prec_wide.columns]

# Reset the index to make 'Cell' a column again
Lutetian_HadCM_old_2PIC_SAT_wide.reset_index(inplace = True)
Lutetian_HadCM_old_2PIC_SST_wide.reset_index(inplace = True)
Lutetian_HadCM_old_2PIC_SSS_wide.reset_index(inplace = True)
Lutetian_HadCM_old_2PIC_prec_wide.reset_index(inplace = True)

# Merge the datasets of SAT, SST, SSS and prec, force suffixes to be added to the column names
# Merge in two steps to circumvent different numbers of cells due to differing spatial resolution in air and ocean models
Lutetian_HadCM_old_2PIC_model = pd.merge(
    # Merge SAT and prec data
    pd.merge(
        Lutetian_HadCM_old_2PIC_SAT_wide.rename(columns = {c: c+'_SAT' for c in Lutetian_HadCM_old_2PIC_SAT_wide.columns if c != 'Cell'}),
        Lutetian_HadCM_old_2PIC_prec_wide.rename(columns = {c: c+'_precip' for c in Lutetian_HadCM_old_2PIC_prec_wide.columns if c != 'Cell'}),
        on = 'Cell',
        how = 'outer'
    ),
    # Merge SST and SSS data
    pd.merge(
        Lutetian_HadCM_old_2PIC_SST_wide.rename(columns = {c: c+'_SST' for c in Lutetian_HadCM_old_2PIC_SST_wide.columns if c != 'Cell'}),
        Lutetian_HadCM_old_2PIC_SSS_wide.rename(columns = {c: c+'_SSS' for c in Lutetian_HadCM_old_2PIC_SSS_wide.columns if c != 'Cell'}),
        on = 'Cell',
        how = 'outer'
    ),
    on = 'Cell',
    how = 'outer'
)

# Display the combined dataset
print("HadCM 2x pre-industrial CO2 combined dataset:")
print(Lutetian_HadCM_old_2PIC_model.head())
HadCM 2x pre-industrial CO2 combined dataset:
   Cell     ja_SAT     fb_SAT     mr_SAT     ar_SAT     my_SAT     jn_SAT  \
0     1  16.109460  16.027917  16.557794  17.969568  20.876367  24.644067   
1     2  14.491327  14.465814  15.096796  16.632349  20.268671  25.111902   
2     3  14.220056  13.856958  14.220026  15.771631  19.406030  24.685876   
3     4  18.878229  18.639429  18.971124  20.211633  22.895258  26.576044   
4     5  10.043237  12.065576  15.218744  18.920587  23.262933  28.577478   

      jl_SAT     ag_SAT     sp_SAT  ...     mr_SSS     ar_SSS     my_SSS  \
0  28.467523  30.818384  29.538446  ...  43.969082  43.947790  43.934935   
1  29.014185  31.189355  29.456750  ...  44.181548  44.176541  44.191296   
2  28.935297  30.628656  28.646417  ...  44.309432  44.306594  44.347039   
3  29.851801  31.372522  30.517450  ...  44.129675  44.117172  44.110881   
4  31.001825  31.300806  27.688562  ...  44.226661  44.231675  44.226539   

      jn_SSS     jl_SSS     ag_SSS     sp_SSS     ot_SSS     nv_SSS     dc_SSS  
0  43.978868  44.011678  44.061833  44.047975  43.960946  43.904051  43.891164  
1  44.264250  44.308143  44.352010  44.343193  44.260797  44.201793  44.162164  
2  44.436311  44.486742  44.510761  44.496772  44.395210  44.342191  44.312135  
3  44.158615  44.235987  44.316041  44.293411  44.185926  44.109325  44.078983  
4  44.259989  44.324560  44.404327  44.392665  44.300962  44.235267  44.207007  

[5 rows x 49 columns]

For HadCM with 4x preindustrial pCO2 (old model)¶

In [12]:
# For old HadCM model with 4x pre-industrial CO2, combine the datasets of SAT, SST, SSS and prec into one dataset for further analysis

# Add a column to number the rows within each month consecutively
Lutetian_HadCM_old_4PIC_SAT['Cell'] = Lutetian_HadCM_old_4PIC_SAT.groupby('Month').cumcount() + 1
Lutetian_HadCM_old_4PIC_SST['Cell'] = Lutetian_HadCM_old_4PIC_SST.groupby('Month').cumcount() + 1
Lutetian_HadCM_old_4PIC_SSS['Cell'] = Lutetian_HadCM_old_4PIC_SSS.groupby('Month').cumcount() + 1
Lutetian_HadCM_old_4PIC_prec['Cell'] = Lutetian_HadCM_old_4PIC_prec.groupby('Month').cumcount() + 1

# Pivot the datasets to create separate columns for each month with 2-letter abbreviations
Lutetian_HadCM_old_4PIC_SAT_wide = Lutetian_HadCM_old_4PIC_SAT.pivot(index='Cell', columns='Month', values='SAT')
Lutetian_HadCM_old_4PIC_SAT_wide.columns = [month_abbreviations[col - 1] for col in Lutetian_HadCM_old_4PIC_SAT_wide.columns]
Lutetian_HadCM_old_4PIC_SST_wide = Lutetian_HadCM_old_4PIC_SST.pivot(index='Cell', columns='Month', values='SST')
Lutetian_HadCM_old_4PIC_SST_wide.columns = [month_abbreviations[col - 1] for col in Lutetian_HadCM_old_4PIC_SST_wide.columns]
Lutetian_HadCM_old_4PIC_SSS_wide = Lutetian_HadCM_old_4PIC_SSS.pivot(index='Cell', columns='Month', values='SSS')
Lutetian_HadCM_old_4PIC_SSS_wide.columns = [month_abbreviations[col - 1] for col in Lutetian_HadCM_old_4PIC_SSS_wide.columns]
Lutetian_HadCM_old_4PIC_prec_wide = Lutetian_HadCM_old_4PIC_prec.pivot(index='Cell', columns='Month', values='Precipitation')
Lutetian_HadCM_old_4PIC_prec_wide.columns = [month_abbreviations[col - 1] for col in Lutetian_HadCM_old_4PIC_prec_wide.columns]

# Reset the index to make 'Cell' a column again
Lutetian_HadCM_old_4PIC_SAT_wide.reset_index(inplace = True)
Lutetian_HadCM_old_4PIC_SST_wide.reset_index(inplace = True)
Lutetian_HadCM_old_4PIC_SSS_wide.reset_index(inplace = True)
Lutetian_HadCM_old_4PIC_prec_wide.reset_index(inplace = True)

# Merge the datasets of SAT, SST, SSS and prec, force suffixes to be added to the column names
# Merge in two steps to circumvent different numbers of cells due to differing spatial resolution in air and ocean models
Lutetian_HadCM_old_4PIC_model = pd.merge(
    # Merge SAT and prec data
    pd.merge(
        Lutetian_HadCM_old_4PIC_SAT_wide.rename(columns = {c: c+'_SAT' for c in Lutetian_HadCM_old_4PIC_SAT_wide.columns if c != 'Cell'}),
        Lutetian_HadCM_old_4PIC_prec_wide.rename(columns = {c: c+'_precip' for c in Lutetian_HadCM_old_4PIC_prec_wide.columns if c != 'Cell'}),
        on = 'Cell',
        how = 'outer'
    ),
    # Merge SST and SSS data
    pd.merge(
        Lutetian_HadCM_old_4PIC_SST_wide.rename(columns = {c: c+'_SST' for c in Lutetian_HadCM_old_4PIC_SST_wide.columns if c != 'Cell'}),
        Lutetian_HadCM_old_4PIC_SSS_wide.rename(columns = {c: c+'_SSS' for c in Lutetian_HadCM_old_4PIC_SSS_wide.columns if c != 'Cell'}),
        on = 'Cell',
        how = 'outer'
    ),
    on = 'Cell',
    how = 'outer'
)

# Display the combined dataset
print("HadCM 4x pre-industrial CO2 combined dataset:")
print(Lutetian_HadCM_old_4PIC_model.head())
HadCM 4x pre-industrial CO2 combined dataset:
   Cell     ja_SAT     fb_SAT     mr_SAT     ar_SAT     my_SAT     jn_SAT  \
0     1  16.109460  16.027917  16.557794  17.969568  20.876367  24.644067   
1     2  14.491327  14.465814  15.096796  16.632349  20.268671  25.111902   
2     3  14.220056  13.856958  14.220026  15.771631  19.406030  24.685876   
3     4  18.878229  18.639429  18.971124  20.211633  22.895258  26.576044   
4     5  10.043237  12.065576  15.218744  18.920587  23.262933  28.577478   

      jl_SAT     ag_SAT     sp_SAT  ...     mr_SSS     ar_SSS     my_SSS  \
0  28.467523  30.818384  29.538446  ...  43.969082  43.947790  43.934935   
1  29.014185  31.189355  29.456750  ...  44.181548  44.176541  44.191296   
2  28.935297  30.628656  28.646417  ...  44.309432  44.306594  44.347039   
3  29.851801  31.372522  30.517450  ...  44.129675  44.117172  44.110881   
4  31.001825  31.300806  27.688562  ...  44.226661  44.231675  44.226539   

      jn_SSS     jl_SSS     ag_SSS     sp_SSS     ot_SSS     nv_SSS     dc_SSS  
0  43.978868  44.011678  44.061833  44.047975  43.960946  43.904051  43.891164  
1  44.264250  44.308143  44.352010  44.343193  44.260797  44.201793  44.162164  
2  44.436311  44.486742  44.510761  44.496772  44.395210  44.342191  44.312135  
3  44.158615  44.235987  44.316041  44.293411  44.185926  44.109325  44.078983  
4  44.259989  44.324560  44.404327  44.392665  44.300962  44.235267  44.207007  

[5 rows x 49 columns]

Calculate the monthly prior for model SST, SAT, SSS and precipitation values¶

For CESM with 4x preindustrial pCO2¶

In [13]:
# Create list of month names
months = ['ja', 'fb', 'mr', 'ar', 'my', 'jn', 'jl', 'ag', 'sp', 'ot', 'nv', 'dc']

# Start by calculating prior means and covariances for CESM model with 4x pre-industrial CO2

# Prior SST, SAT, SSS & precipitation estimates from climate models (mean)
mu_prior_CESM_4PIC_SAT_monthly = np.array(Lutetian_CESM_4PIC_model[[f"{month}_SAT" for month in months]].mean(axis=0, skipna=True))
mu_prior_CESM_4PIC_SST_monthly = np.array(Lutetian_CESM_4PIC_model[[f"{month}_SST" for month in months]].mean(axis=0, skipna=True))
mu_prior_CESM_4PIC_SSS_monthly = np.array(Lutetian_CESM_4PIC_model[[f"{month}_SSS" for month in months]].mean(axis=0, skipna=True))
mu_prior_CESM_4PIC_precip_monthly = np.array(Lutetian_CESM_4PIC_model[[f"{month}_precip" for month in months]].mean(axis=0, skipna=True))

# Covariance between months in prior SST, SAT, SSS, and precip estimates from climate models (covariance matrix)
cov_prior_CESM_4PIC_SAT_monthly = np.cov(Lutetian_CESM_4PIC_model[[f"{month}_SAT" for month in months]].dropna(), rowvar=False)
cov_prior_CESM_4PIC_SST_monthly = np.cov(Lutetian_CESM_4PIC_model[[f"{month}_SST" for month in months]].dropna(), rowvar=False)
cov_prior_CESM_4PIC_SSS_monthly = np.cov(Lutetian_CESM_4PIC_model[[f"{month}_SSS" for month in months]].dropna(), rowvar=False)
cov_prior_CESM_4PIC_precip_monthly = np.cov(Lutetian_CESM_4PIC_model[[f"{month}_precip" for month in months]].dropna(), rowvar=False)

# Store copy of original prior means to keep when later updating the prior
mu_prior_CESM_4PIC_SAT_monthly_original, cov_prior_CESM_4PIC_SAT_monthly_original = mu_prior_CESM_4PIC_SAT_monthly.copy(), cov_prior_CESM_4PIC_SAT_monthly.copy()
mu_prior_CESM_4PIC_SST_monthly_original, cov_prior_CESM_4PIC_SST_monthly_original = mu_prior_CESM_4PIC_SST_monthly.copy(), cov_prior_CESM_4PIC_SST_monthly.copy()
mu_prior_CESM_4PIC_SSS_monthly_original, cov_prior_CESM_4PIC_SSS_monthly_original = mu_prior_CESM_4PIC_SSS_monthly.copy(), cov_prior_CESM_4PIC_SSS_monthly.copy()
mu_prior_CESM_4PIC_precip_monthly_original, cov_prior_CESM_4PIC_precip_monthly_original = mu_prior_CESM_4PIC_precip_monthly.copy(), cov_prior_CESM_4PIC_precip_monthly.copy()

# Extract the standard deviations (uncertainty) from the covariance matrix
std_prior_CESM_4PIC_SAT_monthly = np.sqrt(np.diag(cov_prior_CESM_4PIC_SAT_monthly))
std_prior_CESM_4PIC_SST_monthly = np.sqrt(np.diag(cov_prior_CESM_4PIC_SST_monthly))
std_prior_CESM_4PIC_SSS_monthly = np.sqrt(np.diag(cov_prior_CESM_4PIC_SSS_monthly))
std_prior_CESM_4PIC_precip_monthly = np.sqrt(np.diag(cov_prior_CESM_4PIC_precip_monthly))

print("CESM model with 4x pre-industrial CO2 prior means and standard deviations:")
print("SAT Monthly Means:", mu_prior_CESM_4PIC_SAT_monthly)
print("SAT Monthly Std Devs:", std_prior_CESM_4PIC_SAT_monthly)
print("SST Monthly Means:", mu_prior_CESM_4PIC_SST_monthly)
print("SST Monthly Std Devs:", std_prior_CESM_4PIC_SST_monthly)
print("SSS Monthly Means:", mu_prior_CESM_4PIC_SSS_monthly)
print("SSS Monthly Std Devs:", std_prior_CESM_4PIC_SSS_monthly)
print("Precip Monthly Means:", mu_prior_CESM_4PIC_precip_monthly)
print("Precip Monthly Std Devs:", std_prior_CESM_4PIC_precip_monthly)
CESM model with 4x pre-industrial CO2 prior means and standard deviations:
SAT Monthly Means: [16.27954224 17.01156006 18.66868896 21.54889648 27.12244995 32.0811853
 35.76927734 35.78623779 32.02878784 25.72896606 20.42561768 17.17369751]
SAT Monthly Std Devs: [3.46377896 3.10594374 2.78918732 2.54271169 2.46488387 2.73331005
 2.85535749 2.646315   2.52596201 3.00791784 3.58824735 3.69933077]
SST Monthly Means: [23.86139364 23.17810472 23.14772474 23.92908666 26.57514352 30.58667586
 34.10417351 35.48879139 34.18526063 31.27739675 28.24302759 25.51228172]
SST Monthly Std Devs: [2.83903042 2.98635231 2.95864974 2.74006009 2.42216397 2.22547687
 2.02150675 1.9040936  1.73710814 1.64930877 2.07319756 2.54273385]
SSS Monthly Means: [34.48952147 34.48138433 34.46366809 34.44571124 34.43899317 34.43806975
 34.41677989 34.40664036 34.40840345 34.436755   34.46977234 34.49277948]
SSS Monthly Std Devs: [3.01539682 2.98680818 2.97232063 2.97675101 3.00281989 3.03418516
 3.0716477  3.107458   3.13625919 3.14157102 3.10472103 3.05326323]
Precip Monthly Means: [2.05036495 2.09002108 2.13109892 1.96715635 1.40643449 1.6901619
 2.09515585 1.98018534 1.94212635 1.63982346 1.82765013 1.94334188]
Precip Monthly Std Devs: [0.66564033 0.62619878 0.56043175 0.67673041 0.71392551 0.98128657
 1.25333983 1.00710893 0.75627296 0.48859499 0.68684095 0.68028201]

For CESM with 2x preindustrial pCO2¶

In [14]:
# Now calculate prior means and covariances for CESM model with 2x pre-industrial CO2

# Prior SST, SAT, SSS & precipitation estimates from climate models (mean)
mu_prior_CESM_2PIC_SAT_monthly = np.array(Lutetian_CESM_2PIC_model[[f"{month}_SAT" for month in months]].mean(axis=0, skipna=True))
mu_prior_CESM_2PIC_SST_monthly = np.array(Lutetian_CESM_2PIC_model[[f"{month}_SST" for month in months]].mean(axis=0, skipna=True))
mu_prior_CESM_2PIC_SSS_monthly = np.array(Lutetian_CESM_2PIC_model[[f"{month}_SSS" for month in months]].mean(axis=0, skipna=True))
mu_prior_CESM_2PIC_precip_monthly = np.array(Lutetian_CESM_2PIC_model[[f"{month}_precip" for month in months]].mean(axis=0, skipna=True))

# Covariance between months in prior SST, SAT, SSS, and precip estimates from climate models (covariance matrix)
cov_prior_CESM_2PIC_SAT_monthly = np.cov(Lutetian_CESM_2PIC_model[[f"{month}_SAT" for month in months]].dropna(), rowvar=False)
cov_prior_CESM_2PIC_SST_monthly = np.cov(Lutetian_CESM_2PIC_model[[f"{month}_SST" for month in months]].dropna(), rowvar=False)
cov_prior_CESM_2PIC_SSS_monthly = np.cov(Lutetian_CESM_2PIC_model[[f"{month}_SSS" for month in months]].dropna(), rowvar=False)
cov_prior_CESM_2PIC_precip_monthly = np.cov(Lutetian_CESM_2PIC_model[[f"{month}_precip" for month in months]].dropna(), rowvar=False)

# Store copy of original prior means to keep when later updating the prior
mu_prior_CESM_2PIC_SAT_monthly_original, cov_prior_CESM_2PIC_SAT_monthly_original = mu_prior_CESM_2PIC_SAT_monthly.copy(), cov_prior_CESM_2PIC_SAT_monthly.copy()
mu_prior_CESM_2PIC_SST_monthly_original, cov_prior_CESM_2PIC_SST_monthly_original = mu_prior_CESM_2PIC_SST_monthly.copy(), cov_prior_CESM_2PIC_SST_monthly.copy()
mu_prior_CESM_2PIC_SSS_monthly_original, cov_prior_CESM_2PIC_SSS_monthly_original = mu_prior_CESM_2PIC_SSS_monthly.copy(), cov_prior_CESM_2PIC_SSS_monthly.copy()
mu_prior_CESM_2PIC_precip_monthly_original, cov_prior_CESM_2PIC_precip_monthly_original = mu_prior_CESM_2PIC_precip_monthly.copy(), cov_prior_CESM_2PIC_precip_monthly.copy()

# Extract the standard deviations (uncertainty) from the covariance matrix
std_prior_CESM_2PIC_SAT_monthly = np.sqrt(np.diag(cov_prior_CESM_2PIC_SAT_monthly))
std_prior_CESM_2PIC_SST_monthly = np.sqrt(np.diag(cov_prior_CESM_2PIC_SST_monthly))
std_prior_CESM_2PIC_SSS_monthly = np.sqrt(np.diag(cov_prior_CESM_2PIC_SSS_monthly))
std_prior_CESM_2PIC_precip_monthly = np.sqrt(np.diag(cov_prior_CESM_2PIC_precip_monthly))

print("---")
print("CESM model with 2x pre-industrial CO2 prior means and standard deviations:")
print("SAT Monthly Means:", mu_prior_CESM_2PIC_SAT_monthly)
print("SAT Monthly Std Devs:", std_prior_CESM_2PIC_SAT_monthly)
print("SST Monthly Means:", mu_prior_CESM_2PIC_SST_monthly)
print("SST Monthly Std Devs:", std_prior_CESM_2PIC_SST_monthly)
print("SSS Monthly Means:", mu_prior_CESM_2PIC_SSS_monthly)
print("SSS Monthly Std Devs:", std_prior_CESM_2PIC_SSS_monthly)
print("Precip Monthly Means:", mu_prior_CESM_2PIC_precip_monthly)
print("Precip Monthly Std Devs:", std_prior_CESM_2PIC_precip_monthly)
---
CESM model with 2x pre-industrial CO2 prior means and standard deviations:
SAT Monthly Means: [13.07259888 13.64740356 15.16016968 18.37324585 23.23636963 27.22269897
 30.5027002  30.95843628 27.72623169 21.72160767 16.61921631 13.56875732]
SAT Monthly Std Devs: [3.54443863 3.25051999 2.97972364 2.6082818  2.44318742 2.633592
 2.9258649  2.76327261 2.72785837 3.26765855 3.74834864 3.87666334]
SST Monthly Means: [21.09214209 20.50165407 20.45381792 21.3438108  24.00107607 27.76274415
 31.12298921 32.43020732 31.14308296 28.27901287 25.30350554 22.60309048]
SST Monthly Std Devs: [3.12392276 3.24945387 3.19959003 2.96228485 2.63419216 2.44521968
 2.27340414 2.07587422 1.86449504 1.85875098 2.30023504 2.78693935]
SSS Monthly Means: [34.58157413 34.5569607  34.53000974 34.49177733 34.47721809 34.47541228
 34.46641887 34.48131349 34.52202742 34.56347591 34.58911597 34.59847409]
SSS Monthly Std Devs: [2.8600681  2.83254349 2.81830048 2.83097958 2.86959282 2.90697684
 2.94569794 2.98781149 3.02031307 3.02348573 2.98133699 2.91080858]
Precip Monthly Means: [2.02240836 2.1888688  2.37645928 2.1330658  1.70077639 1.93969147
 2.35826096 2.03186492 1.81291405 1.57573304 2.40556723 2.22682322]
Precip Monthly Std Devs: [0.71949004 0.82266634 0.74623178 0.7373264  0.8970992  1.16473376
 1.52905146 1.05236599 0.73902296 0.47685306 0.73744784 0.91193706]

For new HadCM model with 1x preindustrial pCO2¶

In [15]:
# Calculate prior means and covariances for HadCM model with 1x pre-industrial CO2

# Prior SST, SAT, SSS & precipitation estimates from climate models (mean)
mu_prior_HadCM_new_1PIC_SAT_monthly = np.array(Lutetian_HadCM_new_1PIC_model[[f"{month}_SAT" for month in months]].mean(axis=0, skipna=True))
mu_prior_HadCM_new_1PIC_SST_monthly = np.array(Lutetian_HadCM_new_1PIC_model[[f"{month}_SST" for month in months]].mean(axis=0, skipna=True))
mu_prior_HadCM_new_1PIC_SSS_monthly = np.array(Lutetian_HadCM_new_1PIC_model[[f"{month}_SSS" for month in months]].mean(axis=0, skipna=True))
mu_prior_HadCM_new_1PIC_precip_monthly = np.array(Lutetian_HadCM_new_1PIC_model[[f"{month}_precip" for month in months]].mean(axis=0, skipna=True))

# Covariance between months in prior SST, SAT, SSS, and precip estimates from climate models (covariance matrix)
cov_prior_HadCM_new_1PIC_SAT_monthly = np.cov(Lutetian_HadCM_new_1PIC_model[[f"{month}_SAT" for month in months]].dropna(), rowvar=False)
cov_prior_HadCM_new_1PIC_SST_monthly = np.cov(Lutetian_HadCM_new_1PIC_model[[f"{month}_SST" for month in months]].dropna(), rowvar=False)
cov_prior_HadCM_new_1PIC_SSS_monthly = np.cov(Lutetian_HadCM_new_1PIC_model[[f"{month}_SSS" for month in months]].dropna(), rowvar=False)
cov_prior_HadCM_new_1PIC_precip_monthly = np.cov(Lutetian_HadCM_new_1PIC_model[[f"{month}_precip" for month in months]].dropna(), rowvar=False)

# Store copy of original prior means to keep when later updating the prior
mu_prior_HadCM_new_1PIC_SAT_monthly_original, cov_prior_HadCM_new_1PIC_SAT_monthly_original = mu_prior_HadCM_new_1PIC_SAT_monthly.copy(), cov_prior_HadCM_new_1PIC_SAT_monthly.copy()
mu_prior_HadCM_new_1PIC_SST_monthly_original, cov_prior_HadCM_new_1PIC_SST_monthly_original = mu_prior_HadCM_new_1PIC_SST_monthly.copy(), cov_prior_HadCM_new_1PIC_SST_monthly.copy()
mu_prior_HadCM_new_1PIC_SSS_monthly_original, cov_prior_HadCM_new_1PIC_SSS_monthly_original = mu_prior_HadCM_new_1PIC_SSS_monthly.copy(), cov_prior_HadCM_new_1PIC_SSS_monthly.copy()
mu_prior_HadCM_new_1PIC_precip_monthly_original, cov_prior_HadCM_new_1PIC_precip_monthly_original = mu_prior_HadCM_new_1PIC_precip_monthly.copy(), cov_prior_HadCM_new_1PIC_precip_monthly.copy()

# Extract the standard deviations (uncertainty) from the covariance matrix
std_prior_HadCM_new_1PIC_SAT_monthly = np.sqrt(np.diag(cov_prior_HadCM_new_1PIC_SAT_monthly))
std_prior_HadCM_new_1PIC_SST_monthly = np.sqrt(np.diag(cov_prior_HadCM_new_1PIC_SST_monthly))
std_prior_HadCM_new_1PIC_SSS_monthly = np.sqrt(np.diag(cov_prior_HadCM_new_1PIC_SSS_monthly))
std_prior_HadCM_new_1PIC_precip_monthly = np.sqrt(np.diag(cov_prior_HadCM_new_1PIC_precip_monthly))

print("HadCM model with 1x pre-industrial CO2 prior means and standard deviations:")
print("SAT Monthly Means:", mu_prior_HadCM_new_1PIC_SAT_monthly)
print("SAT Monthly Std Devs:", std_prior_HadCM_new_1PIC_SAT_monthly)
print("SST Monthly Means:", mu_prior_HadCM_new_1PIC_SST_monthly)
print("SST Monthly Std Devs:", std_prior_HadCM_new_1PIC_SST_monthly)
print("SSS Monthly Means:", mu_prior_HadCM_new_1PIC_SSS_monthly)
print("SSS Monthly Std Devs:", std_prior_HadCM_new_1PIC_SSS_monthly)
print("Precip Monthly Means:", mu_prior_HadCM_new_1PIC_precip_monthly)
print("Precip Monthly Std Devs:", std_prior_HadCM_new_1PIC_precip_monthly)
HadCM model with 1x pre-industrial CO2 prior means and standard deviations:
SAT Monthly Means: [10.08334503 10.0055481  10.76345469 12.26940816 15.83041026 20.84376678
 24.38166707 25.21004893 23.2913503  19.00565236 14.61674144 11.84420675]
SAT Monthly Std Devs: [3.96689536 3.6677536  3.37467091 2.96255495 2.3892861  1.69618705
 1.01561685 0.897383   1.69453479 2.75833427 3.47391248 3.86029272]
SST Monthly Means: [13.71185927 12.85175267 12.7495474  13.53442938 16.28040175 21.56905868
 25.37004297 26.3086742  24.58255681 21.0859427  17.70897813 15.26846392]
SST Monthly Std Devs: [3.61325925 3.75286553 3.68884027 3.36160861 2.6673752  1.79873409
 1.04501078 0.80858375 1.61560915 2.50872528 2.97987362 3.32066194]
SSS Monthly Means: [36.29380518 36.28339932 36.28229094 36.29092787 36.28725088 36.26170626
 36.24131509 36.20445716 36.23276794 36.29270599 36.31168112 36.30833951]
SSS Monthly Std Devs: [0.33686695 0.33061834 0.32995713 0.33377789 0.35726196 0.37809867
 0.36099287 0.36809007 0.37801889 0.36607785 0.35702902 0.34699976]
Precip Monthly Means: [2.93467813 2.51780503 2.36863809 2.23043843 2.39540224 2.0227101
 3.48519517 3.86902922 3.50113248 3.86729931 3.88739363 3.5501087 ]
Precip Monthly Std Devs: [0.55099183 0.33959534 0.30486469 0.38027225 0.8389547  1.13985648
 1.28457778 0.88043538 0.83027462 0.81630782 0.57832729 0.61808957]

For new HadCM model with 2x preindustrial pCO2¶

In [16]:
# Calculate prior means and covariances for HadCM model with 2x pre-industrial CO2

# Prior SST, SAT, SSS & precipitation estimates from climate models (mean)
mu_prior_HadCM_new_2PIC_SAT_monthly = np.array(Lutetian_HadCM_new_2PIC_model[[f"{month}_SAT" for month in months]].mean(axis=0, skipna=True))
mu_prior_HadCM_new_2PIC_SST_monthly = np.array(Lutetian_HadCM_new_2PIC_model[[f"{month}_SST" for month in months]].mean(axis=0, skipna=True))
mu_prior_HadCM_new_2PIC_SSS_monthly = np.array(Lutetian_HadCM_new_2PIC_model[[f"{month}_SSS" for month in months]].mean(axis=0, skipna=True))
mu_prior_HadCM_new_2PIC_precip_monthly = np.array(Lutetian_HadCM_new_2PIC_model[[f"{month}_precip" for month in months]].mean(axis=0, skipna=True))

# Covariance between months in prior SST, SAT, SSS, and precip estimates from climate models (covariance matrix)
cov_prior_HadCM_new_2PIC_SAT_monthly = np.cov(Lutetian_HadCM_new_2PIC_model[[f"{month}_SAT" for month in months]].dropna(), rowvar=False)
cov_prior_HadCM_new_2PIC_SST_monthly = np.cov(Lutetian_HadCM_new_2PIC_model[[f"{month}_SST" for month in months]].dropna(), rowvar=False)
cov_prior_HadCM_new_2PIC_SSS_monthly = np.cov(Lutetian_HadCM_new_2PIC_model[[f"{month}_SSS" for month in months]].dropna(), rowvar=False)
cov_prior_HadCM_new_2PIC_precip_monthly = np.cov(Lutetian_HadCM_new_2PIC_model[[f"{month}_precip" for month in months]].dropna(), rowvar=False)

# Store copy of original prior means to keep when later updating the prior
mu_prior_HadCM_new_2PIC_SAT_monthly_original, cov_prior_HadCM_new_2PIC_SAT_monthly_original = mu_prior_HadCM_new_2PIC_SAT_monthly.copy(), cov_prior_HadCM_new_2PIC_SAT_monthly.copy()
mu_prior_HadCM_new_2PIC_SST_monthly_original, cov_prior_HadCM_new_2PIC_SST_monthly_original = mu_prior_HadCM_new_2PIC_SST_monthly.copy(), cov_prior_HadCM_new_2PIC_SST_monthly.copy()
mu_prior_HadCM_new_2PIC_SSS_monthly_original, cov_prior_HadCM_new_2PIC_SSS_monthly_original = mu_prior_HadCM_new_2PIC_SSS_monthly.copy(), cov_prior_HadCM_new_2PIC_SSS_monthly.copy()
mu_prior_HadCM_new_2PIC_precip_monthly_original, cov_prior_HadCM_new_2PIC_precip_monthly_original = mu_prior_HadCM_new_2PIC_precip_monthly.copy(), cov_prior_HadCM_new_2PIC_precip_monthly.copy()

# Extract the standard deviations (uncertainty) from the covariance matrix
std_prior_HadCM_new_2PIC_SAT_monthly = np.sqrt(np.diag(cov_prior_HadCM_new_2PIC_SAT_monthly))
std_prior_HadCM_new_2PIC_SST_monthly = np.sqrt(np.diag(cov_prior_HadCM_new_2PIC_SST_monthly))
std_prior_HadCM_new_2PIC_SSS_monthly = np.sqrt(np.diag(cov_prior_HadCM_new_2PIC_SSS_monthly))
std_prior_HadCM_new_2PIC_precip_monthly = np.sqrt(np.diag(cov_prior_HadCM_new_2PIC_precip_monthly))

print("HadCM model with 2x pre-industrial CO2 prior means and standard deviations:")
print("SAT Monthly Means:", mu_prior_HadCM_new_2PIC_SAT_monthly)
print("SAT Monthly Std Devs:", std_prior_HadCM_new_2PIC_SAT_monthly)
print("SST Monthly Means:", mu_prior_HadCM_new_2PIC_SST_monthly)
print("SST Monthly Std Devs:", std_prior_HadCM_new_2PIC_SST_monthly)
print("SSS Monthly Means:", mu_prior_HadCM_new_2PIC_SSS_monthly)
print("SSS Monthly Std Devs:", std_prior_HadCM_new_2PIC_SSS_monthly)
print("Precip Monthly Means:", mu_prior_HadCM_new_2PIC_precip_monthly)
print("Precip Monthly Std Devs:", std_prior_HadCM_new_2PIC_precip_monthly)
HadCM model with 2x pre-industrial CO2 prior means and standard deviations:
SAT Monthly Means: [13.87478027 13.46100006 14.24293162 15.6019455  19.14669444 24.01290283
 27.19336853 27.86939901 26.06070608 22.21917877 18.0738032  15.42517497]
SAT Monthly Std Devs: [3.41347899 3.22229019 2.87469713 2.50385319 1.86477108 0.98233555
 0.60279527 0.70411706 1.43557583 2.29931143 2.93579974 3.37321414]
SST Monthly Means: [16.72936006 15.87916062 15.81255115 16.6499893  19.50177904 24.63571306
 28.09234827 28.87249704 27.32484054 23.97480947 20.65000586 18.21593779]
SST Monthly Std Devs: [3.12896351 3.27754316 3.19489358 2.86552162 2.12298285 1.12347457
 0.63620505 0.61010611 1.32532831 2.07901319 2.50455562 2.86486584]
SSS Monthly Means: [36.58636508 36.57094957 36.57021872 36.58156468 36.56322799 36.53252962
 36.54307583 36.51518076 36.55099426 36.60907426 36.62052294 36.60791749]
SSS Monthly Std Devs: [0.34892745 0.34228328 0.34178826 0.34698161 0.37435212 0.40162332
 0.37570892 0.38237697 0.3973393  0.37730392 0.36687449 0.35679726]
Precip Monthly Means: [3.80580454 3.16736692 2.40405854 2.33888872 2.90959791 1.9625486
 3.35601807 3.95611436 3.35655003 3.81088675 4.52821999 4.18951223]
Precip Monthly Std Devs: [0.74624594 0.55008635 0.35552588 0.43694453 1.02178189 1.04182468
 1.29200533 1.14999034 0.7361767  0.88765985 0.78936416 0.72873753]

For new HadCM model with 1056 ppm pCO2¶

In [17]:
# Calculate prior means and covariances for HadCM model with 1056 ppm CO2

# Prior SST, SAT, SSS & precipitation estimates from climate models (mean)
mu_prior_HadCM_new_1056ppm_SAT_monthly = np.array(Lutetian_HadCM_new_1056ppm_model[[f"{month}_SAT" for month in months]].mean(axis=0, skipna=True))
mu_prior_HadCM_new_1056ppm_SST_monthly = np.array(Lutetian_HadCM_new_1056ppm_model[[f"{month}_SST" for month in months]].mean(axis=0, skipna=True))
mu_prior_HadCM_new_1056ppm_SSS_monthly = np.array(Lutetian_HadCM_new_1056ppm_model[[f"{month}_SSS" for month in months]].mean(axis=0, skipna=True))
mu_prior_HadCM_new_1056ppm_precip_monthly = np.array(Lutetian_HadCM_new_1056ppm_model[[f"{month}_precip" for month in months]].mean(axis=0, skipna=True))

# Covariance between months in prior SST, SAT, SSS, and precip estimates from climate models (covariance matrix)
cov_prior_HadCM_new_1056ppm_SAT_monthly = np.cov(Lutetian_HadCM_new_1056ppm_model[[f"{month}_SAT" for month in months]].dropna(), rowvar=False)
cov_prior_HadCM_new_1056ppm_SST_monthly = np.cov(Lutetian_HadCM_new_1056ppm_model[[f"{month}_SST" for month in months]].dropna(), rowvar=False)
cov_prior_HadCM_new_1056ppm_SSS_monthly = np.cov(Lutetian_HadCM_new_1056ppm_model[[f"{month}_SSS" for month in months]].dropna(), rowvar=False)
cov_prior_HadCM_new_1056ppm_precip_monthly = np.cov(Lutetian_HadCM_new_1056ppm_model[[f"{month}_precip" for month in months]].dropna(), rowvar=False)

# Store copy of original prior means to keep when later updating the prior
mu_prior_HadCM_new_1056ppm_SAT_monthly_original, cov_prior_HadCM_new_1056ppm_SAT_monthly_original = mu_prior_HadCM_new_1056ppm_SAT_monthly.copy(), cov_prior_HadCM_new_1056ppm_SAT_monthly.copy()
mu_prior_HadCM_new_1056ppm_SST_monthly_original, cov_prior_HadCM_new_1056ppm_SST_monthly_original = mu_prior_HadCM_new_1056ppm_SST_monthly.copy(), cov_prior_HadCM_new_1056ppm_SST_monthly.copy()
mu_prior_HadCM_new_1056ppm_SSS_monthly_original, cov_prior_HadCM_new_1056ppm_SSS_monthly_original = mu_prior_HadCM_new_1056ppm_SSS_monthly.copy(), cov_prior_HadCM_new_1056ppm_SSS_monthly.copy()
mu_prior_HadCM_new_1056ppm_precip_monthly_original, cov_prior_HadCM_new_1056ppm_precip_monthly_original = mu_prior_HadCM_new_1056ppm_precip_monthly.copy(), cov_prior_HadCM_new_1056ppm_precip_monthly.copy()

# Extract the standard deviations (uncertainty) from the covariance matrix
std_prior_HadCM_new_1056ppm_SAT_monthly = np.sqrt(np.diag(cov_prior_HadCM_new_1056ppm_SAT_monthly))
std_prior_HadCM_new_1056ppm_SST_monthly = np.sqrt(np.diag(cov_prior_HadCM_new_1056ppm_SST_monthly))
std_prior_HadCM_new_1056ppm_SSS_monthly = np.sqrt(np.diag(cov_prior_HadCM_new_1056ppm_SSS_monthly))
std_prior_HadCM_new_1056ppm_precip_monthly = np.sqrt(np.diag(cov_prior_HadCM_new_1056ppm_precip_monthly))

print("HadCM model with 1056 ppm CO2 prior means and standard deviations:")
print("SAT Monthly Means:", mu_prior_HadCM_new_1056ppm_SAT_monthly)
print("SAT Monthly Std Devs:", std_prior_HadCM_new_1056ppm_SAT_monthly)
print("SST Monthly Means:", mu_prior_HadCM_new_1056ppm_SST_monthly)
print("SST Monthly Std Devs:", std_prior_HadCM_new_1056ppm_SST_monthly)
print("SSS Monthly Means:", mu_prior_HadCM_new_1056ppm_SSS_monthly)
print("SSS Monthly Std Devs:", std_prior_HadCM_new_1056ppm_SSS_monthly)
print("Precip Monthly Means:", mu_prior_HadCM_new_1056ppm_precip_monthly)
print("Precip Monthly Std Devs:", std_prior_HadCM_new_1056ppm_precip_monthly)
HadCM model with 1056 ppm CO2 prior means and standard deviations:
SAT Monthly Means: [16.54376119 16.33315684 16.66519572 18.1570933  21.33070018 26.04470978
 29.27867788 30.05242564 28.38777822 24.68946991 20.37269491 17.89802958]
SAT Monthly Std Devs: [3.1136452  2.87241146 2.6653854  2.24775679 1.63278962 0.69198219
 0.47930615 0.56291876 1.14972847 2.03401859 2.74423138 3.08483859]
SST Monthly Means: [18.93725482 18.20055996 18.07463733 18.94948942 21.65623561 26.49933052
 29.90868568 30.89709473 29.50700535 26.32116821 22.74434818 20.38640473]
SST Monthly Std Devs: [2.92543007 3.03146388 2.97552998 2.62686596 1.8848678  0.81764338
 0.59191858 0.57527782 1.10605321 1.82464118 2.31451485 2.66401625]
SSS Monthly Means: [36.81117155 36.78617369 36.78417348 36.79833389 36.79387419 36.76191701
 36.79473585 36.81089483 36.85219832 36.87364457 36.871775   36.84308146]
SSS Monthly Std Devs: [0.36005944 0.36024212 0.3596727  0.3678925  0.39256506 0.42024895
 0.41518531 0.43954986 0.44087248 0.4074775  0.37944107 0.36737629]
Precip Monthly Means: [4.56713648 3.91851193 2.74238199 2.21756103 2.6688204  2.25554827
 2.59721839 3.43563859 3.46278601 4.34280869 4.56264103 4.84894508]
Precip Monthly Std Devs: [0.85407461 0.70612807 0.50598617 0.43407756 1.00076624 1.0245456
 1.00411221 1.11605905 0.828573   1.1991117  0.95570044 1.00690122]

For old HadCM model with 2x preindustrial pCO2¶

In [18]:
# Calculate prior means and covariances for HadCM model with 2x pre-industrial CO2

# Prior SST, SAT, SSS & precipitation estimates from climate models (mean)
mu_prior_HadCM_old_2PIC_SAT_monthly = np.array(Lutetian_HadCM_old_2PIC_model[[f"{month}_SAT" for month in months]].mean(axis=0, skipna=True))
mu_prior_HadCM_old_2PIC_SST_monthly = np.array(Lutetian_HadCM_old_2PIC_model[[f"{month}_SST" for month in months]].mean(axis=0, skipna=True))
mu_prior_HadCM_old_2PIC_SSS_monthly = np.array(Lutetian_HadCM_old_2PIC_model[[f"{month}_SSS" for month in months]].mean(axis=0, skipna=True))
mu_prior_HadCM_old_2PIC_precip_monthly = np.array(Lutetian_HadCM_old_2PIC_model[[f"{month}_precip" for month in months]].mean(axis=0, skipna=True))

# Covariance between months in prior SST, SAT, SSS, and precip estimates from climate models (covariance matrix)
cov_prior_HadCM_old_2PIC_SAT_monthly = np.cov(Lutetian_HadCM_old_2PIC_model[[f"{month}_SAT" for month in months]].dropna(), rowvar=False)
cov_prior_HadCM_old_2PIC_SST_monthly = np.cov(Lutetian_HadCM_old_2PIC_model[[f"{month}_SST" for month in months]].dropna(), rowvar=False)
cov_prior_HadCM_old_2PIC_SSS_monthly = np.cov(Lutetian_HadCM_old_2PIC_model[[f"{month}_SSS" for month in months]].dropna(), rowvar=False)
cov_prior_HadCM_old_2PIC_precip_monthly = np.cov(Lutetian_HadCM_old_2PIC_model[[f"{month}_precip" for month in months]].dropna(), rowvar=False)

# Store copy of original prior means to keep when later updating the prior
mu_prior_HadCM_old_2PIC_SAT_monthly_original, cov_prior_HadCM_old_2PIC_SAT_monthly_original = mu_prior_HadCM_old_2PIC_SAT_monthly.copy(), cov_prior_HadCM_old_2PIC_SAT_monthly.copy()
mu_prior_HadCM_old_2PIC_SST_monthly_original, cov_prior_HadCM_old_2PIC_SST_monthly_original = mu_prior_HadCM_old_2PIC_SST_monthly.copy(), cov_prior_HadCM_old_2PIC_SST_monthly.copy()
mu_prior_HadCM_old_2PIC_SSS_monthly_original, cov_prior_HadCM_old_2PIC_SSS_monthly_original = mu_prior_HadCM_old_2PIC_SSS_monthly.copy(), cov_prior_HadCM_old_2PIC_SSS_monthly.copy()
mu_prior_HadCM_old_2PIC_precip_monthly_original, cov_prior_HadCM_old_2PIC_precip_monthly_original = mu_prior_HadCM_old_2PIC_precip_monthly.copy(), cov_prior_HadCM_old_2PIC_precip_monthly.copy()

# Extract the standard deviations (uncertainty) from the covariance matrix
std_prior_HadCM_old_2PIC_SAT_monthly = np.sqrt(np.diag(cov_prior_HadCM_old_2PIC_SAT_monthly))
std_prior_HadCM_old_2PIC_SST_monthly = np.sqrt(np.diag(cov_prior_HadCM_old_2PIC_SST_monthly))
std_prior_HadCM_old_2PIC_SSS_monthly = np.sqrt(np.diag(cov_prior_HadCM_old_2PIC_SSS_monthly))
std_prior_HadCM_old_2PIC_precip_monthly = np.sqrt(np.diag(cov_prior_HadCM_old_2PIC_precip_monthly))

print("HadCM model with 2x pre-industrial CO2 prior means and standard deviations:")
print("SAT Monthly Means:", mu_prior_HadCM_old_2PIC_SAT_monthly)
print("SAT Monthly Std Devs:", std_prior_HadCM_old_2PIC_SAT_monthly)
print("SST Monthly Means:", mu_prior_HadCM_old_2PIC_SST_monthly)
print("SST Monthly Std Devs:", std_prior_HadCM_old_2PIC_SST_monthly)
print("SSS Monthly Means:", mu_prior_HadCM_old_2PIC_SSS_monthly)
print("SSS Monthly Std Devs:", std_prior_HadCM_old_2PIC_SSS_monthly)
print("Precip Monthly Means:", mu_prior_HadCM_old_2PIC_precip_monthly)
print("Precip Monthly Std Devs:", std_prior_HadCM_old_2PIC_precip_monthly)
HadCM model with 2x pre-industrial CO2 prior means and standard deviations:
SAT Monthly Means: [17.37342478 17.21628214 17.78856557 19.24039866 22.18971914 26.23706462
 29.33261007 30.70993194 29.73895416 26.07219594 21.69050496 18.52393239]
SAT Monthly Std Devs: [3.2114442  2.69102368 2.25082291 1.96523166 1.63807297 1.35401718
 0.73510388 0.49971448 0.91035189 1.98977278 2.90543435 3.37134836]
SST Monthly Means: [19.7125903  18.99473997 18.88936858 19.91672048 22.810782   26.93403435
 29.85972058 31.31134917 30.67377489 27.4390127  23.87150418 21.16645553]
SST Monthly Std Devs: [2.24990485 2.29966025 2.31215823 2.12468382 1.64393886 1.0585021
 0.44918179 0.47817612 0.69576981 1.50967361 1.95781611 2.15044945]
SSS Monthly Means: [43.70795882 43.73280867 43.72686184 43.67948156 43.64607803 43.67422238
 43.74063267 43.80258416 43.77589559 43.71899047 43.69268966 43.6958935 ]
SSS Monthly Std Devs: [0.7396979  0.72425698 0.74107798 0.79608893 0.84202305 0.85804696
 0.84220463 0.84309064 0.87106857 0.84498618 0.81758351 0.77582677]
Precip Monthly Means: [4.51414761 2.96477545 2.0466914  1.70405398 1.499306   0.98548384
 1.2141631  1.94227658 3.96484522 4.89490475 5.10539876 4.79175341]
Precip Monthly Std Devs: [0.54851291 0.54980863 0.52847315 0.61988324 0.67752496 0.34351868
 0.40517783 0.93230212 0.90520864 0.74675508 0.64169083 0.55874858]

For old HadCM model with 4x preindustrial pCO2¶

In [19]:
# Calculate prior means and covariances for HadCM model with 4x pre-industrial CO2

# Prior SST, SAT, SSS & precipitation estimates from climate models (mean)
mu_prior_HadCM_old_4PIC_SAT_monthly = np.array(Lutetian_HadCM_old_4PIC_model[[f"{month}_SAT" for month in months]].mean(axis=0, skipna=True))
mu_prior_HadCM_old_4PIC_SST_monthly = np.array(Lutetian_HadCM_old_4PIC_model[[f"{month}_SST" for month in months]].mean(axis=0, skipna=True))
mu_prior_HadCM_old_4PIC_SSS_monthly = np.array(Lutetian_HadCM_old_4PIC_model[[f"{month}_SSS" for month in months]].mean(axis=0, skipna=True))
mu_prior_HadCM_old_4PIC_precip_monthly = np.array(Lutetian_HadCM_old_4PIC_model[[f"{month}_precip" for month in months]].mean(axis=0, skipna=True))

# Covariance between months in prior SST, SAT, SSS, and precip estimates from climate models (covariance matrix)
cov_prior_HadCM_old_4PIC_SAT_monthly = np.cov(Lutetian_HadCM_old_4PIC_model[[f"{month}_SAT" for month in months]].dropna(), rowvar=False)
cov_prior_HadCM_old_4PIC_SST_monthly = np.cov(Lutetian_HadCM_old_4PIC_model[[f"{month}_SST" for month in months]].dropna(), rowvar=False)
cov_prior_HadCM_old_4PIC_SSS_monthly = np.cov(Lutetian_HadCM_old_4PIC_model[[f"{month}_SSS" for month in months]].dropna(), rowvar=False)
cov_prior_HadCM_old_4PIC_precip_monthly = np.cov(Lutetian_HadCM_old_4PIC_model[[f"{month}_precip" for month in months]].dropna(), rowvar=False)

# Store copy of original prior means to keep when later updating the prior
mu_prior_HadCM_old_4PIC_SAT_monthly_original, cov_prior_HadCM_old_4PIC_SAT_monthly_original = mu_prior_HadCM_old_4PIC_SAT_monthly.copy(), cov_prior_HadCM_old_4PIC_SAT_monthly.copy()
mu_prior_HadCM_old_4PIC_SST_monthly_original, cov_prior_HadCM_old_4PIC_SST_monthly_original = mu_prior_HadCM_old_4PIC_SST_monthly.copy(), cov_prior_HadCM_old_4PIC_SST_monthly.copy()
mu_prior_HadCM_old_4PIC_SSS_monthly_original, cov_prior_HadCM_old_4PIC_SSS_monthly_original = mu_prior_HadCM_old_4PIC_SSS_monthly.copy(), cov_prior_HadCM_old_4PIC_SSS_monthly.copy()
mu_prior_HadCM_old_4PIC_precip_monthly_original, cov_prior_HadCM_old_4PIC_precip_monthly_original = mu_prior_HadCM_old_4PIC_precip_monthly.copy(), cov_prior_HadCM_old_4PIC_precip_monthly.copy()

# Extract the standard deviations (uncertainty) from the covariance matrix
std_prior_HadCM_old_4PIC_SAT_monthly = np.sqrt(np.diag(cov_prior_HadCM_old_4PIC_SAT_monthly))
std_prior_HadCM_old_4PIC_SST_monthly = np.sqrt(np.diag(cov_prior_HadCM_old_4PIC_SST_monthly))
std_prior_HadCM_old_4PIC_SSS_monthly = np.sqrt(np.diag(cov_prior_HadCM_old_4PIC_SSS_monthly))
std_prior_HadCM_old_4PIC_precip_monthly = np.sqrt(np.diag(cov_prior_HadCM_old_4PIC_precip_monthly))

print("HadCM model with 4x pre-industrial CO2 prior means and standard deviations:")
print("SAT Monthly Means:", mu_prior_HadCM_old_4PIC_SAT_monthly)
print("SAT Monthly Std Devs:", std_prior_HadCM_old_4PIC_SAT_monthly)
print("SST Monthly Means:", mu_prior_HadCM_old_4PIC_SST_monthly)
print("SST Monthly Std Devs:", std_prior_HadCM_old_4PIC_SST_monthly)
print("SSS Monthly Means:", mu_prior_HadCM_old_4PIC_SSS_monthly)
print("SSS Monthly Std Devs:", std_prior_HadCM_old_4PIC_SSS_monthly)
print("Precip Monthly Means:", mu_prior_HadCM_old_4PIC_precip_monthly)
print("Precip Monthly Std Devs:", std_prior_HadCM_old_4PIC_precip_monthly)
HadCM model with 4x pre-industrial CO2 prior means and standard deviations:
SAT Monthly Means: [17.37342478 17.21628214 17.78856557 19.24039866 22.18971914 26.23706462
 29.33261007 30.70993194 29.73895416 26.07219594 21.69050496 18.52393239]
SAT Monthly Std Devs: [3.2114442  2.69102368 2.25082291 1.96523166 1.63807297 1.35401718
 0.73510388 0.49971448 0.91035189 1.98977278 2.90543435 3.37134836]
SST Monthly Means: [19.7125903  18.99473997 18.88936858 19.91672048 22.810782   26.93403435
 29.85972058 31.31134917 30.67377489 27.4390127  23.87150418 21.16645553]
SST Monthly Std Devs: [2.24990485 2.29966025 2.31215823 2.12468382 1.64393886 1.0585021
 0.44918179 0.47817612 0.69576981 1.50967361 1.95781611 2.15044945]
SSS Monthly Means: [43.70795882 43.73280867 43.72686184 43.67948156 43.64607803 43.67422238
 43.74063267 43.80258416 43.77589559 43.71899047 43.69268966 43.6958935 ]
SSS Monthly Std Devs: [0.7396979  0.72425698 0.74107798 0.79608893 0.84202305 0.85804696
 0.84220463 0.84309064 0.87106857 0.84498618 0.81758351 0.77582677]
Precip Monthly Means: [4.51414761 2.96477545 2.0466914  1.70405398 1.499306   0.98548384
 1.2141631  1.94227658 3.96484522 4.89490475 5.10539876 4.79175341]
Precip Monthly Std Devs: [0.54851291 0.54980863 0.52847315 0.61988324 0.67752496 0.34351868
 0.40517783 0.93230212 0.90520864 0.74675508 0.64169083 0.55874858]

Plot the monthly priors for all model values¶

In [20]:
# Set dimensions of data
n_models_CESM_4PIC_monthly = len(Lutetian_CESM_4PIC_model["Cell"])  # Find the total number of models
n_models_CESM_2PIC_monthly = len(Lutetian_CESM_2PIC_model["Cell"])  # Find the total number of models
n_models_HadCM_new_1PIC_monthly = len(Lutetian_HadCM_new_1PIC_model["Cell"])  # Find the total number of models
n_models_HadCM_new_2PIC_monthly = len(Lutetian_HadCM_new_2PIC_model["Cell"])  # Find the total number of models
n_models_HadCM_new_1056ppm_monthly = len(Lutetian_HadCM_new_1056ppm_model["Cell"])  # Find the total number of models
n_models_HadCM_old_2PIC_monthly = len(Lutetian_HadCM_old_2PIC_model["Cell"])  # Find the total number of models
n_models_HadCM_old_4PIC_monthly = len(Lutetian_HadCM_old_4PIC_model["Cell"])  # Find the total number of models

# Create a monthly scale for the x-axis
month_names = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']  # List full month names
months_scale = np.arange(len(months)) + 1  # Create monthly scale

# Create the figure and axes
fig, axes = plt.subplots(2, 7, figsize=(25, 10), sharex=True, sharey="row")

# ------------- Plot prior distributions for CESM\nmodel with 4x pre-industrial CO2 ------------- #

# Panel 1: Plot the prior distribution for SST and SAT for CESM\nmodel with 4x pre-industrial CO2
axes[0, 0].plot(months_scale, mu_prior_CESM_4PIC_SAT_monthly, label='Prior SAT Mean', marker='o', color='r')
axes[0, 0].plot(months_scale, mu_prior_CESM_4PIC_SST_monthly, label='Prior SST Mean', marker='o', color='b')

# Add 95% confidence intervals for SAT
axes[0, 0].fill_between(
    months_scale,
    mu_prior_CESM_4PIC_SAT_monthly - stats.t.ppf(1 - 0.025, n_models_CESM_4PIC_monthly) * std_prior_CESM_4PIC_SAT_monthly / np.sqrt(n_models_CESM_4PIC_monthly),
    mu_prior_CESM_4PIC_SAT_monthly + stats.t.ppf(1 - 0.025, n_models_CESM_4PIC_monthly) * std_prior_CESM_4PIC_SAT_monthly / np.sqrt(n_models_CESM_4PIC_monthly),
    alpha=0.2, color='r', label='SAT 95% CI'
)

# Add 95% confidence intervals for SST
axes[0, 0].fill_between(
    months_scale,
    mu_prior_CESM_4PIC_SST_monthly - stats.t.ppf(1 - 0.025, n_models_CESM_4PIC_monthly) * std_prior_CESM_4PIC_SST_monthly / np.sqrt(n_models_CESM_4PIC_monthly),
    mu_prior_CESM_4PIC_SST_monthly + stats.t.ppf(1 - 0.025, n_models_CESM_4PIC_monthly) * std_prior_CESM_4PIC_SST_monthly / np.sqrt(n_models_CESM_4PIC_monthly),
    alpha=0.2, color='b', label='SST 95% CI'
)

axes[0, 0].set_ylim(5, 40)  # Set lower limit of temperature y-axis to 15 and upper limit to 40
axes[0, 0].set_title('CESM\n4x pre-industrial CO2')
axes[0, 0].set_ylabel('Temperature (°C)')
axes[0, 0].legend(loc = "upper left")
axes[0, 0].grid(True)

# Panel 2: Plot the prior distribution for SSS and precipitation for CESM\nmodel with 4x pre-industrial CO2
axes[1, 0].plot(months_scale, mu_prior_CESM_4PIC_SSS_monthly, label='Prior SSS Mean', marker='o', color='g')
ax2 = axes[1, 0].twinx()  # Create a secondary y-axis for precipitation
ax2.plot(months_scale, mu_prior_CESM_4PIC_precip_monthly, label='Prior Precipitation Mean', marker='o', color='purple')

# Add 95% confidence intervals for SSS
axes[1, 0].fill_between(
    months_scale,
    mu_prior_CESM_4PIC_SSS_monthly - stats.t.ppf(1 - 0.025, n_models_CESM_4PIC_monthly) * std_prior_CESM_4PIC_SSS_monthly / np.sqrt(n_models_CESM_4PIC_monthly),
    mu_prior_CESM_4PIC_SSS_monthly + stats.t.ppf(1 - 0.025, n_models_CESM_4PIC_monthly) * std_prior_CESM_4PIC_SSS_monthly / np.sqrt(n_models_CESM_4PIC_monthly),
    alpha=0.2, color='g', label='SSS 95% CI'
)

# Add 95% confidence intervals for precipitation
ax2.fill_between(
    months_scale,
    mu_prior_CESM_4PIC_precip_monthly - stats.t.ppf(1 - 0.025, n_models_CESM_4PIC_monthly) * std_prior_CESM_4PIC_precip_monthly / np.sqrt(n_models_CESM_4PIC_monthly),
    mu_prior_CESM_4PIC_precip_monthly + stats.t.ppf(1 - 0.025, n_models_CESM_4PIC_monthly) * std_prior_CESM_4PIC_precip_monthly / np.sqrt(n_models_CESM_4PIC_monthly),
    alpha=0.2, color='purple', label='Precipitation 95% CI'
)

axes[1, 0].set_ylabel('SSS (psu)', color='g')
axes[1, 0].set_ylim(30, 50)  # Set lower limit of SSS y-axis to 30 and upper limit to 45
ax2.set_ylabel('')
ax2.set_ylim(0, 7)  # Set lower limit of precipitation y-axis to 0 and upper limit to 7
ax2.set_yticklabels([]) # Hide y-tick labels for SSS to reduce clutter
axes[1, 0].set_title('CESM\n4x pre-industrial CO2')
axes[1, 0].legend(loc='upper left')
ax2.legend(loc='upper right')
axes[1, 0].grid(True)

# ------------- Plot prior distributions for CESM\nmodel with 2x pre-industrial CO2 ------------- #

# Panel 3: Plot the prior distribution for SST and SAT for CESM\nmodel with 2x pre-industrial CO2
axes[0, 1].plot(months_scale, mu_prior_CESM_2PIC_SAT_monthly, label='Prior SAT Mean', marker='o', color='r')
axes[0, 1].plot(months_scale, mu_prior_CESM_2PIC_SST_monthly, label='Prior SST Mean', marker='o', color='b')

# Add 95% confidence intervals for SAT
axes[0, 1].fill_between(
    months_scale,
    mu_prior_CESM_2PIC_SAT_monthly - stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_SAT_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
    mu_prior_CESM_2PIC_SAT_monthly + stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_SAT_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
    alpha=0.2, color='r', label='SAT 95% CI'
)

# Add 95% confidence intervals for SST
axes[0, 1].fill_between(
    months_scale,
    mu_prior_CESM_2PIC_SST_monthly - stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_SST_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
    mu_prior_CESM_2PIC_SST_monthly + stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_SST_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
    alpha=0.2, color='b', label='SST 95% CI'
)

axes[0, 1].set_ylim(5, 40)  # Set lower limit of temperature y-axis to 15 and upper limit to 40
axes[0, 1].set_title('CESM\n2x pre-industrial CO2')
axes[0, 1].set_ylabel('')
axes[0, 1].legend(loc = "upper left")
axes[0, 1].grid(True)

# Panel 4: Plot the prior distribution for SSS and precipitation for CESM\nmodel with 2x pre-industrial CO2
axes[1, 1].plot(months_scale, mu_prior_CESM_2PIC_SSS_monthly, label='Prior SSS Mean', marker='o', color='g')
ax4 = axes[1, 1].twinx() # Create a secondary y-axis for precipitation
ax4.plot(months_scale, mu_prior_CESM_2PIC_precip_monthly, label='Prior Precipitation Mean', marker='o', color='purple')

# Add 95% confidence intervals for SSS
axes[1, 1].fill_between(
    months_scale,
    mu_prior_CESM_2PIC_SSS_monthly - stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_SSS_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
    mu_prior_CESM_2PIC_SSS_monthly + stats.t.ppf(1 - 0.025, n_models_CESM_4PIC_monthly) * std_prior_CESM_4PIC_SSS_monthly / np.sqrt(n_models_CESM_4PIC_monthly),
    alpha=0.2, color='g', label='SSS 95% CI'
)

# Add 95% confidence intervals for precipitation
ax4.fill_between(
    months_scale,
    mu_prior_CESM_2PIC_precip_monthly - stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_precip_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
    mu_prior_CESM_2PIC_precip_monthly + stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_precip_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
    alpha=0.2, color='purple', label='Precipitation 95% CI'
)

axes[1, 1].set_ylabel('')
axes[1, 1].set_ylim(30, 50)  # Set lower limit of SSS y-axis to 30 and upper limit to 45
# axes[1, 1].set_yticklabels([])  # Hide SSS y-axis tick labels
# ax4.set_ylabel('Precipitation (mm/day)', color='purple')
ax4.set_yticklabels([])  # Hide precipitation y-axis tick labels
ax4.set_ylim(0, 7)  # Set lower limit of precipitation y-axis to 0 and upper limit to 7
axes[1, 1].set_title('CESM\n2x pre-industrial CO2')
axes[1, 1].legend(loc="upper left")
ax4.legend(loc="upper right")
axes[1, 1].grid(True)

# ------------- Plot prior distributions for new HadCM model with 1x pre-industrial CO2 ------------- #

# Panel 5: Plot the prior distribution for SST and SAT for HadCM model with 1x pre-industrial CO2
axes[0, 2].plot(months_scale, mu_prior_HadCM_new_1PIC_SAT_monthly, label='Prior SAT Mean', marker='o', color='r')
axes[0, 2].plot(months_scale, mu_prior_HadCM_new_1PIC_SST_monthly, label='Prior SST Mean', marker='o', color='b')

# Add 95% confidence intervals for SAT
axes[0, 2].fill_between(
    months_scale,
    mu_prior_HadCM_new_1PIC_SAT_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_1PIC_monthly) * std_prior_HadCM_new_1PIC_SAT_monthly / np.sqrt(n_models_HadCM_new_1PIC_monthly),
    mu_prior_HadCM_new_1PIC_SAT_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_1PIC_monthly) * std_prior_HadCM_new_1PIC_SAT_monthly / np.sqrt(n_models_HadCM_new_1PIC_monthly),
    alpha=0.2, color='r', label='SAT 95% CI'
)

# Add 95% confidence intervals for SST
axes[0, 2].fill_between(
    months_scale,
    mu_prior_HadCM_new_1PIC_SST_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_1PIC_monthly) * std_prior_HadCM_new_1PIC_SST_monthly / np.sqrt(n_models_HadCM_new_1PIC_monthly),
    mu_prior_HadCM_new_1PIC_SST_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_1PIC_monthly) * std_prior_HadCM_new_1PIC_SST_monthly / np.sqrt(n_models_HadCM_new_1PIC_monthly),
    alpha=0.2, color='b', label='SST 95% CI'
)

axes[0, 2].set_ylim(5, 40)  # Set lower limit of temperature y-axis to 15 and upper limit to 40
axes[0, 2].set_title('HadCM (new)\n1x pre-industrial CO2')
axes[0, 2].set_ylabel('')
axes[0, 2].legend(loc = "upper left")
axes[0, 2].grid(True)

# Panel 6: Plot the prior distribution for SSS and precipitation for HadCM model with 1x pre-industrial CO2
axes[1, 2].plot(months_scale, mu_prior_HadCM_new_1PIC_SSS_monthly, label='Prior SSS Mean', marker='o', color='g')
ax6 = axes[1, 2].twinx()  # Create a secondary y-axis for precipitation
ax6.plot(months_scale, mu_prior_HadCM_new_1PIC_precip_monthly, label='Prior Precipitation Mean', marker='o', color='purple')

# Add 95% confidence intervals for SSS
axes[1, 2].fill_between(
    months_scale,
    mu_prior_HadCM_new_1PIC_SSS_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_1PIC_monthly) * std_prior_HadCM_new_1PIC_SSS_monthly / np.sqrt(n_models_HadCM_new_1PIC_monthly),
    mu_prior_HadCM_new_1PIC_SSS_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_1PIC_monthly) * std_prior_HadCM_new_1PIC_SSS_monthly / np.sqrt(n_models_HadCM_new_1PIC_monthly),
    alpha=0.2, color='g', label='SSS 95% CI'
)

# Add 95% confidence intervals for precipitation
ax6.fill_between(
    months_scale,
    mu_prior_HadCM_new_1PIC_precip_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_1PIC_monthly) * std_prior_HadCM_new_1PIC_precip_monthly / np.sqrt(n_models_HadCM_new_1PIC_monthly),
    mu_prior_HadCM_new_1PIC_precip_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_1PIC_monthly) * std_prior_HadCM_new_1PIC_precip_monthly / np.sqrt(n_models_HadCM_new_1PIC_monthly),
    alpha=0.2, color='purple', label='Precipitation 95% CI'
)

axes[1, 2].set_ylabel('')
axes[1, 2].set_ylim(30, 50)  # Set lower limit of SSS y-axis to 30 and upper limit to 45
# axes[1, 2].set_yticklabels([])  # Hide SSS y-axis tick labels
# ax6.set_ylabel('Precipitation (mm/day)', color='purple')
ax6.set_yticklabels([])  # Hide precipitation y-axis tick labels
ax6.set_ylim(0, 7)  # Set lower limit of precipitation y-axis to 0 and upper limit to 7
axes[1, 2].set_title('HadCM (new)\n1x pre-industrial CO2')
axes[1, 2].legend(loc="upper left")
ax6.legend(loc="upper right")
axes[1, 2].grid(True)

# --------------- Plot prior distributions for new HadCM model with 2x pre-industrial CO2 --------------- #

# Panel 7: Plot the prior distribution for SST and SAT for HadCM model with 2x pre-industrial CO2
axes[0, 3].plot(months_scale, mu_prior_HadCM_new_2PIC_SAT_monthly, label='Prior SAT Mean', marker='o', color='r')
axes[0, 3].plot(months_scale, mu_prior_HadCM_new_2PIC_SST_monthly, label='Prior SST Mean', marker='o', color='b')

# Add 95% confidence intervals for SAT
axes[0, 3].fill_between(
    months_scale,
    mu_prior_HadCM_new_2PIC_SAT_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_2PIC_monthly) * std_prior_HadCM_new_2PIC_SAT_monthly / np.sqrt(n_models_HadCM_new_2PIC_monthly),
    mu_prior_HadCM_new_2PIC_SAT_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_2PIC_monthly) * std_prior_HadCM_new_2PIC_SAT_monthly / np.sqrt(n_models_HadCM_new_2PIC_monthly),
    alpha=0.2, color='r', label='SAT 95% CI'
)

# Add 95% confidence intervals for SST
axes[0, 3].fill_between(
    months_scale,
    mu_prior_HadCM_new_2PIC_SST_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_2PIC_monthly) * std_prior_HadCM_new_2PIC_SST_monthly / np.sqrt(n_models_HadCM_new_2PIC_monthly),
    mu_prior_HadCM_new_2PIC_SST_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_2PIC_monthly) * std_prior_HadCM_new_2PIC_SST_monthly / np.sqrt(n_models_HadCM_new_2PIC_monthly),
    alpha=0.2, color='b', label='SST 95% CI'
)

axes[0, 3].set_ylim(5, 40)  # Set lower limit of temperature y-axis to 15 and upper limit to 40
axes[0, 3].set_title('HadCM (new)\n2x pre-industrial CO2')
axes[0, 3].set_ylabel('')
axes[0, 3].legend(loc = "upper left")
axes[0, 3].grid(True)

# Panel 8: Plot the prior distribution for SSS and precipitation for HadCM model with 2x pre-industrial CO2
axes[1, 3].plot(months_scale, mu_prior_HadCM_new_2PIC_SSS_monthly, label='Prior SSS Mean', marker='o', color='g')
ax8 = axes[1, 3].twinx()  # Create a secondary y-axis for precipitation
ax8.plot(months_scale, mu_prior_HadCM_new_2PIC_precip_monthly, label='Prior Precipitation Mean', marker='o', color='purple')

# Add 95% confidence intervals for SSS
axes[1, 3].fill_between(
    months_scale,
    mu_prior_HadCM_new_2PIC_SSS_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_2PIC_monthly) * std_prior_HadCM_new_2PIC_SSS_monthly / np.sqrt(n_models_HadCM_new_2PIC_monthly),
    mu_prior_HadCM_new_2PIC_SSS_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_2PIC_monthly) * std_prior_HadCM_new_2PIC_SSS_monthly / np.sqrt(n_models_HadCM_new_2PIC_monthly),
    alpha=0.2, color='g', label='SSS 95% CI'
)

# Add 95% confidence intervals for precipitation
ax8.fill_between(
    months_scale,
    mu_prior_HadCM_new_2PIC_precip_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_2PIC_monthly) * std_prior_HadCM_new_2PIC_precip_monthly / np.sqrt(n_models_HadCM_new_2PIC_monthly),
    mu_prior_HadCM_new_2PIC_precip_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_2PIC_monthly) * std_prior_HadCM_new_2PIC_precip_monthly / np.sqrt(n_models_HadCM_new_2PIC_monthly),
    alpha=0.2, color='purple', label='Precipitation 95% CI'
)

axes[1, 3].set_ylabel('')
axes[1, 3].set_ylim(30, 50)  # Set lower limit of SSS y-axis to 30 and upper limit to 45
# axes[1, 3].set_yticklabels([])  # Hide SSS y-axis tick labels
# ax8.set_ylabel('Precipitation (mm/day)', color='purple')
ax8.set_yticklabels([])  # Hide precipitation y-axis tick labels
ax8.set_ylim(0, 7)  # Set lower limit of precipitation y-axis to 0 and upper limit to 7
axes[1, 3].set_title('HadCM (new)\n2x pre-industrial CO2')
axes[1, 3].legend(loc="upper left")
ax8.legend(loc="upper right")
axes[1, 3].grid(True)

# --------------- Plot prior distributions for new HadCM model with 1056ppm CO2 --------------- #

# Panel 9: Plot the prior distribution for SST and SAT for HadCM model with 1056ppm CO2
axes[0, 4].plot(months_scale, mu_prior_HadCM_new_1056ppm_SAT_monthly, label='Prior SAT Mean', marker='o', color='r')
axes[0, 4].plot(months_scale, mu_prior_HadCM_new_1056ppm_SST_monthly, label='Prior SST Mean', marker='o', color='b')

# Add 95% confidence intervals for SAT
axes[0, 4].fill_between(
    months_scale,
    mu_prior_HadCM_new_1056ppm_SAT_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_1056ppm_monthly) * std_prior_HadCM_new_1056ppm_SAT_monthly / np.sqrt(n_models_HadCM_new_1056ppm_monthly),
    mu_prior_HadCM_new_1056ppm_SAT_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_1056ppm_monthly) * std_prior_HadCM_new_1056ppm_SAT_monthly / np.sqrt(n_models_HadCM_new_1056ppm_monthly),
    alpha=0.2, color='r', label='SAT 95% CI'
)

# Add 95% confidence intervals for SST
axes[0, 4].fill_between(
    months_scale,
    mu_prior_HadCM_new_1056ppm_SST_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_1056ppm_monthly) * std_prior_HadCM_new_1056ppm_SST_monthly / np.sqrt(n_models_HadCM_new_1056ppm_monthly),
    mu_prior_HadCM_new_1056ppm_SST_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_1056ppm_monthly) * std_prior_HadCM_new_1056ppm_SST_monthly / np.sqrt(n_models_HadCM_new_1056ppm_monthly),
    alpha=0.2, color='b', label='SST 95% CI'
)

axes[0, 4].set_ylim(5, 40)  # Set lower limit of temperature y-axis to 15 and upper limit to 40
axes[0, 4].set_title('HadCM (new)\n1056ppm CO2')
axes[0, 4].set_ylabel('')
axes[0, 4].legend(loc = "upper left")
axes[0, 4].grid(True)

# Panel 10: Plot the prior distribution for SSS and precipitation for HadCM model with 1056ppm CO2
axes[1, 4].plot(months_scale, mu_prior_HadCM_new_1056ppm_SSS_monthly, label='Prior SSS Mean', marker='o', color='g')
ax10 = axes[1, 4].twinx()  # Create a secondary y-axis for precipitation
ax10.plot(months_scale, mu_prior_HadCM_new_1056ppm_precip_monthly, label='Prior Precipitation Mean', marker='o', color='purple')

# Add 95% confidence intervals for SSS
axes[1, 4].fill_between(
    months_scale,
    mu_prior_HadCM_new_1056ppm_SSS_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_1056ppm_monthly) * std_prior_HadCM_new_1056ppm_SSS_monthly / np.sqrt(n_models_HadCM_new_1056ppm_monthly),
    mu_prior_HadCM_new_1056ppm_SSS_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_1056ppm_monthly) * std_prior_HadCM_new_1056ppm_SSS_monthly / np.sqrt(n_models_HadCM_new_1056ppm_monthly),
    alpha=0.2, color='g', label='SSS 95% CI'
)

# Add 95% confidence intervals for precipitation
ax10.fill_between(
    months_scale,
    mu_prior_HadCM_new_1056ppm_precip_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_1056ppm_monthly) * std_prior_HadCM_new_1056ppm_precip_monthly / np.sqrt(n_models_HadCM_new_1056ppm_monthly),
    mu_prior_HadCM_new_1056ppm_precip_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_1056ppm_monthly) * std_prior_HadCM_new_1056ppm_precip_monthly / np.sqrt(n_models_HadCM_new_1056ppm_monthly),
    alpha=0.2, color='purple', label='Precipitation 95% CI'
)

axes[1, 4].set_ylabel('')
axes[1, 4].set_ylim(30, 50)  # Set lower limit of SSS y-axis to 30 and upper limit to 45
# axes[1, 4].set_yticklabels([])  # Hide SSS y-axis tick labels
# ax10.set_ylabel('Precipitation (mm/day)', color='purple')
ax10.set_yticklabels([])  # Hide precipitation y-axis tick labels
ax10.set_ylim(0, 7)  # Set lower limit of precipitation y-axis to 0 and upper limit to 7
axes[1, 4].set_title('HadCM (new)\n1056ppm CO2')
axes[1, 4].legend(loc="upper left")
ax10.legend(loc="upper right")
axes[1, 4].grid(True)

# --------------- Plot prior distributions for old HadCM model with 4x pre-industrial CO2 --------------- #

# Panel 11: Plot the prior distribution for SST and SAT for HadCM model with 4x pre-industrial CO2
axes[0, 5].plot(months_scale, mu_prior_HadCM_old_4PIC_SAT_monthly, label='Prior SAT Mean', marker='o', color='r')
axes[0, 5].plot(months_scale, mu_prior_HadCM_old_4PIC_SST_monthly, label='Prior SST Mean', marker='o', color='b')

# Add 95% confidence intervals for SAT
axes[0, 5].fill_between(
    months_scale,
    mu_prior_HadCM_old_4PIC_SAT_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_old_4PIC_monthly) * std_prior_HadCM_old_4PIC_SAT_monthly / np.sqrt(n_models_HadCM_old_4PIC_monthly),
    mu_prior_HadCM_old_4PIC_SAT_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_old_4PIC_monthly) * std_prior_HadCM_old_4PIC_SAT_monthly / np.sqrt(n_models_HadCM_old_4PIC_monthly),
    alpha=0.2, color='r', label='SAT 95% CI'
)

# Add 95% confidence intervals for SST
axes[0, 5].fill_between(
    months_scale,
    mu_prior_HadCM_old_4PIC_SST_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_old_4PIC_monthly) * std_prior_HadCM_old_4PIC_SST_monthly / np.sqrt(n_models_HadCM_old_4PIC_monthly),
    mu_prior_HadCM_old_4PIC_SST_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_old_4PIC_monthly) * std_prior_HadCM_old_4PIC_SST_monthly / np.sqrt(n_models_HadCM_old_4PIC_monthly),
    alpha=0.2, color='b', label='SST 95% CI'
)

axes[0, 5].set_ylim(5, 40)  # Set lower limit of temperature y-axis to 15 and upper limit to 40
axes[0, 5].set_title('HadCM (old)\n4x pre-industrial CO2')
axes[0, 5].set_ylabel('')
axes[0, 5].legend(loc = "upper left")
axes[0, 5].grid(True)

# Panel 12: Plot the prior distribution for SSS and precipitation for HadCM model with 4x pre-industrial CO2
axes[1, 5].plot(months_scale, mu_prior_HadCM_old_4PIC_SSS_monthly, label='Prior SSS Mean', marker='o', color='g')
ax12 = axes[1, 5].twinx()  # Create a secondary y-axis for precipitation
ax12.plot(months_scale, mu_prior_HadCM_old_4PIC_precip_monthly, label='Prior Precipitation Mean', marker='o', color='purple')

# Add 95% confidence intervals for SSS
axes[1, 5].fill_between(
    months_scale,
    mu_prior_HadCM_old_4PIC_SSS_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_old_4PIC_monthly) * std_prior_HadCM_old_4PIC_SSS_monthly / np.sqrt(n_models_HadCM_old_4PIC_monthly),
    mu_prior_HadCM_old_4PIC_SSS_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_old_4PIC_monthly) * std_prior_HadCM_old_4PIC_SSS_monthly / np.sqrt(n_models_HadCM_old_4PIC_monthly),
    alpha=0.2, color='g', label='SSS 95% CI'
)

# Add 95% confidence intervals for precipitation
ax12.fill_between(
    months_scale,
    mu_prior_HadCM_old_4PIC_precip_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_old_4PIC_monthly) * std_prior_HadCM_old_4PIC_precip_monthly / np.sqrt(n_models_HadCM_old_4PIC_monthly),
    mu_prior_HadCM_old_4PIC_precip_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_old_4PIC_monthly) * std_prior_HadCM_old_4PIC_precip_monthly / np.sqrt(n_models_HadCM_old_4PIC_monthly),
    alpha=0.2, color='purple', label='Precipitation 95% CI'
)

axes[1, 5].set_ylabel('')
axes[1, 5].set_ylim(30, 50)  # Set lower limit of SSS y-axis to 30 and upper limit to 45
# axes[1, 5].set_yticklabels([])  # Hide SSS y-axis tick labels
# ax12.set_ylabel('Precipitation (mm/day)', color='purple')
ax12.set_yticklabels([])  # Hide precipitation y-axis tick labels
ax12.set_ylim(0, 7)  # Set lower limit of precipitation y-axis to 0 and upper limit to 7
axes[1, 5].set_title('HadCM (old)\n4x pre-industrial CO2')
axes[1, 5].legend(loc="upper left")
ax12.legend(loc="upper right")
axes[1, 5].grid(True)

# --------------- Plot prior distributions for old HadCM model with 2x pre-industrial CO2 --------------- #

# Panel 13: Plot the prior distribution for SST and SAT for HadCM model with 2x pre-industrial CO2
axes[0, 6].plot(months_scale, mu_prior_HadCM_old_2PIC_SAT_monthly, label='Prior SAT Mean', marker='o', color='r')
axes[0, 6].plot(months_scale, mu_prior_HadCM_old_2PIC_SST_monthly, label='Prior SST Mean', marker='o', color='b')

# Add 95% confidence intervals for SAT
axes[0, 6].fill_between(
    months_scale,
    mu_prior_HadCM_old_2PIC_SAT_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_old_2PIC_monthly) * std_prior_HadCM_old_2PIC_SAT_monthly / np.sqrt(n_models_HadCM_old_2PIC_monthly),
    mu_prior_HadCM_old_2PIC_SAT_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_old_2PIC_monthly) * std_prior_HadCM_old_2PIC_SAT_monthly / np.sqrt(n_models_HadCM_old_2PIC_monthly),
    alpha=0.2, color='r', label='SAT 95% CI'
)

# Add 95% confidence intervals for SST
axes[0, 6].fill_between(
    months_scale,
    mu_prior_HadCM_old_2PIC_SST_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_old_2PIC_monthly) * std_prior_HadCM_old_2PIC_SST_monthly / np.sqrt(n_models_HadCM_old_2PIC_monthly),
    mu_prior_HadCM_old_2PIC_SST_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_old_2PIC_monthly) * std_prior_HadCM_old_2PIC_SST_monthly / np.sqrt(n_models_HadCM_old_2PIC_monthly),
    alpha=0.2, color='b', label='SST 95% CI'
)

axes[0, 6].set_ylim(5, 40)  # Set lower limit of temperature y-axis to 15 and upper limit to 40
axes[0, 6].set_title('HadCM (old)\n2x pre-industrial CO2')
axes[0, 6].set_ylabel('')
axes[0, 6].legend(loc = "upper left")
axes[0, 6].grid(True)

# Panel 14: Plot the prior distribution for SSS and precipitation for HadCM model with 2x pre-industrial CO2
axes[1, 6].plot(months_scale, mu_prior_HadCM_old_2PIC_SSS_monthly, label='Prior SSS Mean', marker='o', color='g')
ax14 = axes[1, 6].twinx()  # Create a secondary y-axis for precipitation
ax14.plot(months_scale, mu_prior_HadCM_old_2PIC_precip_monthly, label='Prior Precipitation Mean', marker='o', color='purple')

# Add 95% confidence intervals for SSS
axes[1, 6].fill_between(
    months_scale,
    mu_prior_HadCM_old_2PIC_SSS_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_old_2PIC_monthly) * std_prior_HadCM_old_2PIC_SSS_monthly / np.sqrt(n_models_HadCM_old_2PIC_monthly),
    mu_prior_HadCM_old_2PIC_SSS_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_old_2PIC_monthly) * std_prior_HadCM_old_2PIC_SSS_monthly / np.sqrt(n_models_HadCM_old_2PIC_monthly),
    alpha=0.2, color='g', label='SSS 95% CI'
)

# Add 95% confidence intervals for precipitation
ax14.fill_between(
    months_scale,
    mu_prior_HadCM_old_2PIC_precip_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_old_2PIC_monthly) * std_prior_HadCM_old_2PIC_precip_monthly / np.sqrt(n_models_HadCM_old_2PIC_monthly),
    mu_prior_HadCM_old_2PIC_precip_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_old_2PIC_monthly) * std_prior_HadCM_old_2PIC_precip_monthly / np.sqrt(n_models_HadCM_old_2PIC_monthly),
    alpha=0.2, color='purple', label='Precipitation 95% CI'
)

axes[1, 6].set_ylabel('')
axes[1, 6].set_ylim(30, 50)  # Set lower limit of SSS y-axis to 30 and upper limit to 45
# axes[1, 6].set_yticklabels([])  # Hide SSS y-axis tick labels
ax14.set_ylabel('Precipitation (mm/day)', color='purple')
ax14.set_ylim(0, 7)  # Set lower limit of precipitation y-axis to 0 and upper limit to 7
axes[1, 6].set_title('HadCM (old)\n2x pre-industrial CO2')
axes[1, 6].legend(loc="upper left")
ax14.legend(loc="upper right")
axes[1, 6].grid(True)

# Update the x-axis with month names
for ax in axes[1, :]:
    ax.set_xticks(months_scale)
    ax.set_xticklabels(month_names, rotation=45)

# Add overall figure title
fig.suptitle('Prior Distributions of Monthly SST, SAT, SSS, and Precipitation for Various Climate Models with different pCO2 forcing', fontsize=16)
Out[20]:
Text(0.5, 0.98, 'Prior Distributions of Monthly SST, SAT, SSS, and Precipitation for Various Climate Models with different pCO2 forcing')
No description has been provided for this image

Convert SAT and SST model data to D47 domain using the regression by Daëron and Vermeesch (2023) and propagate uncertainty in the calibration¶

For CESM with 4x perindustrial pCO2¶

In [21]:
# Apply T47()-function from the D47calib package to all SAT columns

# First for the CESM model with 4x pre-industrial CO2
# Identify the SAT and SST columns
SAT_CESM_4PIC_columns = [col for col in Lutetian_CESM_4PIC_model.columns if col.endswith('_SAT')]
SST_CESM_4PIC_columns = [col for col in Lutetian_CESM_4PIC_model.columns if col.endswith('_SST')]

# Apply the conversion function to the SAT columns and add new columns for D47 and D47_SE
for col in SAT_CESM_4PIC_columns:
    base_col_name = col.replace('_SAT', '') # Remove the '_SAT' suffix from the column name
    Lutetian_CESM_4PIC_model[f'{base_col_name}_SAT_D47'], Lutetian_CESM_4PIC_model[f'{base_col_name}_SAT_D47_SE'] = zip(*Lutetian_CESM_4PIC_model[col].apply(
        lambda x: D47c.OGLS23.T47(T = x) if not pd.isna(x) else (np.nan, np.nan)
    )) # Use zip() to unpack the tuple returned by the apply() method and apply the T47()-function to each value in the column
for col in SST_CESM_4PIC_columns:
    base_col_name = col.replace('_SST', '') # Remove the '_SST' suffix from the column name
    Lutetian_CESM_4PIC_model[f'{base_col_name}_SST_D47'], Lutetian_CESM_4PIC_model[f'{base_col_name}_SST_D47_SE'] = zip(*Lutetian_CESM_4PIC_model[col].apply(
        lambda x: D47c.OGLS23.T47(T = x) if not pd.isna(x) else (np.nan, np.nan)
    )) # Use zip() to unpack the tuple returned by the apply() method and apply the T47()-function to each value in the column

# Display the combined data with D47 and D47_SE columns
D47_CESM_4PIC_columns = [col for col in Lutetian_CESM_4PIC_model.columns if col.endswith('_D47')]
D47_se_CESM_4PIC_columns = [col for col in Lutetian_CESM_4PIC_model.columns if '_D47_SE' in col]
print("D47 values for all CESM model 4x preindustrial pCO2 outcomes:\n", Lutetian_CESM_4PIC_model[D47_CESM_4PIC_columns].head())
print("Calibration standard errors for all CESM model 4x preindustrial pCO2 outcomes:\n", Lutetian_CESM_4PIC_model[D47_se_CESM_4PIC_columns].head())
D47 values for all CESM model 4x preindustrial pCO2 outcomes:
    ja_SAT_D47  fb_SAT_D47  mr_SAT_D47  ar_SAT_D47  my_SAT_D47  jn_SAT_D47  \
0    0.637865    0.635067    0.629115    0.619502    0.601307    0.584664   
1    0.603134    0.602008    0.598014    0.591188    0.578009    0.564439   
2    0.602866    0.601969    0.598808    0.592691    0.580329    0.567315   
3    0.601023    0.600939    0.598426    0.592938    0.581667    0.568903   
4    0.604475    0.603903    0.599502    0.591387    0.576345    0.561918   

   jl_SAT_D47  ag_SAT_D47  sp_SAT_D47  ot_SAT_D47  ...  mr_SST_D47  \
0    0.575942    0.575647    0.588334    0.607248  ...    0.593324   
1    0.554885    0.553952    0.563022    0.577000  ...    0.594240   
2    0.556444    0.554857    0.563225    0.577214  ...    0.595136   
3    0.557261    0.555379    0.563453    0.576950  ...    0.618591   
4    0.549188    0.549164    0.560136    0.577425  ...    0.618968   

   ar_SST_D47  my_SST_D47  jn_SST_D47  jl_SST_D47  ag_SST_D47  sp_SST_D47  \
0    0.591086    0.583574    0.572417    0.564044    0.559876    0.562770   
1    0.592472    0.585470    0.574402    0.566375    0.562104    0.564462   
2    0.593459    0.586555    0.575418    0.567460    0.563169    0.565401   
3    0.615362    0.605418    0.592590    0.582142    0.577727    0.579656   
4    0.615934    0.606080    0.593130    0.582374    0.577869    0.579768   

   ot_SST_D47  nv_SST_D47  dc_SST_D47  
0    0.570493    0.579090    0.586671  
1    0.571625    0.580172    0.587853  
2    0.572431    0.581026    0.589019  
3    0.586429    0.597502    0.608002  
4    0.586786    0.597919    0.608058  

[5 rows x 24 columns]
Calibration standard errors for all CESM model 4x preindustrial pCO2 outcomes:
    ja_SAT_D47_SE  fb_SAT_D47_SE  mr_SAT_D47_SE  ar_SAT_D47_SE  my_SAT_D47_SE  \
0       0.001252       0.001233       0.001196       0.001144       0.001073   
1       0.001079       0.001075       0.001065       0.001051       0.001041   
2       0.001078       0.001075       0.001067       0.001054       0.001041   
3       0.001073       0.001072       0.001066       0.001054       0.001042   
4       0.001083       0.001081       0.001069       0.001052       0.001041   

   jn_SAT_D47_SE  jl_SAT_D47_SE  ag_SAT_D47_SE  sp_SAT_D47_SE  ot_SAT_D47_SE  \
0       0.001044       0.001041       0.001041       0.001047       0.001092   
1       0.001051       0.001070       0.001072       0.001053       0.001041   
2       0.001047       0.001066       0.001070       0.001053       0.001041   
3       0.001046       0.001064       0.001069       0.001053       0.001041   
4       0.001055       0.001085       0.001085       0.001059       0.001041   

   ...  mr_SST_D47_SE  ar_SST_D47_SE  my_SST_D47_SE  jn_SST_D47_SE  \
0  ...       0.001055       0.001051       0.001043       0.001043   
1  ...       0.001057       0.001053       0.001044       0.001042   
2  ...       0.001058       0.001055       0.001045       0.001041   
3  ...       0.001140       0.001125       0.001086       0.001054   
4  ...       0.001141       0.001127       0.001088       0.001055   

   jl_SST_D47_SE  ag_SST_D47_SE  sp_SST_D47_SE  ot_SST_D47_SE  nv_SST_D47_SE  \
0       0.001052       0.001059       0.001054       0.001044       0.001041   
1       0.001049       0.001055       0.001051       0.001043       0.001041   
2       0.001047       0.001053       0.001050       0.001043       0.001042   
3       0.001042       0.001041       0.001041       0.001045       0.001064   
4       0.001042       0.001041       0.001041       0.001046       0.001065   

   dc_SST_D47_SE  
0       0.001045  
1       0.001047  
2       0.001048  
3       0.001095  
4       0.001095  

[5 rows x 24 columns]

For CESM with 2x perindustrial pCO2¶

In [22]:
# Convert temperature data for the CESM model with 2x pre-industrial CO2
# Identify the SAT and SST columns
SAT_CESM_2PIC_columns = [col for col in Lutetian_CESM_2PIC_model.columns if col.endswith('_SAT')]
SST_CESM_2PIC_columns = [col for col in Lutetian_CESM_2PIC_model.columns if col.endswith('_SST')]

# Apply the conversion function to the SAT columns and add new columns for D47 and D47_SE
for col in SAT_CESM_2PIC_columns:
    base_col_name = col.replace('_SAT', '') # Remove the '_SAT' suffix from the column name
    Lutetian_CESM_2PIC_model[f'{base_col_name}_SAT_D47'], Lutetian_CESM_2PIC_model[f'{base_col_name}_SAT_D47_SE'] = zip(*Lutetian_CESM_2PIC_model[col].apply(
        lambda x: D47c.OGLS23.T47(T = x) if not pd.isna(x) else (np.nan, np.nan)
    )) # Use zip() to unpack the tuple returned by the apply() method and apply the T47()-function to each value in the column
for col in SST_CESM_2PIC_columns:
    base_col_name = col.replace('_SST', '') # Remove the '_SST' suffix from the column name
    Lutetian_CESM_2PIC_model[f'{base_col_name}_SST_D47'], Lutetian_CESM_2PIC_model[f'{base_col_name}_SST_D47_SE'] = zip(*Lutetian_CESM_2PIC_model[col].apply(
        lambda x: D47c.OGLS23.T47(T = x) if not pd.isna(x) else (np.nan, np.nan)
    )) # Use zip() to unpack the tuple returned by the apply() method and apply the T47()-function to each value in the column

# Display the combined data with D47 and D47_SE columns
D47_CESM_2PIC_columns = [col for col in Lutetian_CESM_2PIC_model.columns if col.endswith('_D47')]
D47_se_CESM_2PIC_columns = [col for col in Lutetian_CESM_2PIC_model.columns if '_D47_SE' in col]
print("D47 values for all CESM model 2x preindustrial pCO2 outcomes:\n", Lutetian_CESM_2PIC_model[D47_CESM_2PIC_columns].head())
print("Calibration standard errors for all CESM model 2x preindustrial pCO2 outcomes:\n", Lutetian_CESM_2PIC_model[D47_se_CESM_2PIC_columns].head())
D47 values for all CESM model 2x preindustrial pCO2 outcomes:
    ja_SAT_D47  fb_SAT_D47  mr_SAT_D47  ar_SAT_D47  my_SAT_D47  jn_SAT_D47  \
0    0.649217    0.647051    0.641333    0.629812    0.613530    0.600021   
1    0.612951    0.611943    0.607858    0.600181    0.587709    0.575798   
2    0.612374    0.611535    0.608217    0.601482    0.589772    0.577980   
3    0.610292    0.610277    0.607520    0.601490    0.590680    0.579040   
4    0.614221    0.613823    0.609521    0.601010    0.586881    0.574258   

   jl_SAT_D47  ag_SAT_D47  sp_SAT_D47  ot_SAT_D47  ...  mr_SST_D47  \
0    0.591412    0.590661    0.600895    0.619948  ...    0.601218   
1    0.566713    0.565232    0.573181    0.587373  ...    0.602052   
2    0.567341    0.565589    0.573023    0.587203  ...    0.602959   
3    0.567591    0.565777    0.573334    0.586829  ...    0.629461   
4    0.561525    0.560765    0.571039    0.588141  ...    0.629846   

   ar_SST_D47  my_SST_D47  jn_SST_D47  jl_SST_D47  ag_SST_D47  sp_SST_D47  \
0    0.598485    0.590787    0.579938    0.571354    0.567425    0.570273   
1    0.599915    0.592725    0.582065    0.573740    0.569557    0.571820   
2    0.600939    0.593798    0.583144    0.574862    0.570641    0.572771   
3    0.625603    0.615248    0.602450    0.592397    0.587444    0.589301   
4    0.626263    0.615955    0.603027    0.592655    0.587575    0.589482   

   ot_SST_D47  nv_SST_D47  dc_SST_D47  
0    0.578342    0.587379    0.595560  
1    0.579378    0.588410    0.596721  
2    0.580137    0.589270    0.597940  
3    0.596974    0.608338    0.619456  
4    0.597385    0.608808    0.619465  

[5 rows x 24 columns]
Calibration standard errors for all CESM model 2x preindustrial pCO2 outcomes:
    ja_SAT_D47_SE  fb_SAT_D47_SE  mr_SAT_D47_SE  ar_SAT_D47_SE  my_SAT_D47_SE  \
0       0.001335       0.001318       0.001276       0.001200       0.001117   
1       0.001114       0.001110       0.001094       0.001070       0.001047   
2       0.001112       0.001108       0.001096       0.001074       0.001049   
3       0.001103       0.001103       0.001093       0.001074       0.001051   
4       0.001120       0.001118       0.001101       0.001073       0.001046   

   jn_SAT_D47_SE  jl_SAT_D47_SE  ag_SAT_D47_SE  sp_SAT_D47_SE  ot_SAT_D47_SE  \
0       0.001070       0.001052       0.001050       0.001072       0.001146   
1       0.001041       0.001048       0.001050       0.001042       0.001046   
2       0.001041       0.001047       0.001050       0.001042       0.001046   
3       0.001041       0.001047       0.001049       0.001042       0.001046   
4       0.001042       0.001056       0.001057       0.001044       0.001047   

   ...  mr_SST_D47_SE  ar_SST_D47_SE  my_SST_D47_SE  jn_SST_D47_SE  \
0  ...       0.001073       0.001066       0.001051       0.001041   
1  ...       0.001076       0.001070       0.001054       0.001042   
2  ...       0.001078       0.001072       0.001056       0.001043   
3  ...       0.001198       0.001176       0.001124       0.001077   
4  ...       0.001201       0.001180       0.001127       0.001078   

   jl_SST_D47_SE  ag_SST_D47_SE  sp_SST_D47_SE  ot_SST_D47_SE  nv_SST_D47_SE  \
0       0.001043       0.001047       0.001044       0.001041       0.001046   
1       0.001042       0.001045       0.001043       0.001041       0.001047   
2       0.001042       0.001044       0.001043       0.001041       0.001049   
3       0.001053       0.001046       0.001049       0.001062       0.001096   
4       0.001054       0.001046       0.001049       0.001063       0.001098   

   dc_SST_D47_SE  
0       0.001059  
1       0.001062  
2       0.001065  
3       0.001144  
4       0.001144  

[5 rows x 24 columns]
   ja_SAT_D47_SE  fb_SAT_D47_SE  mr_SAT_D47_SE  ar_SAT_D47_SE  my_SAT_D47_SE  \
0       0.001335       0.001318       0.001276       0.001200       0.001117   
1       0.001114       0.001110       0.001094       0.001070       0.001047   
2       0.001112       0.001108       0.001096       0.001074       0.001049   
3       0.001103       0.001103       0.001093       0.001074       0.001051   
4       0.001120       0.001118       0.001101       0.001073       0.001046   

   jn_SAT_D47_SE  jl_SAT_D47_SE  ag_SAT_D47_SE  sp_SAT_D47_SE  ot_SAT_D47_SE  \
0       0.001070       0.001052       0.001050       0.001072       0.001146   
1       0.001041       0.001048       0.001050       0.001042       0.001046   
2       0.001041       0.001047       0.001050       0.001042       0.001046   
3       0.001041       0.001047       0.001049       0.001042       0.001046   
4       0.001042       0.001056       0.001057       0.001044       0.001047   

   ...  mr_SST_D47_SE  ar_SST_D47_SE  my_SST_D47_SE  jn_SST_D47_SE  \
0  ...       0.001073       0.001066       0.001051       0.001041   
1  ...       0.001076       0.001070       0.001054       0.001042   
2  ...       0.001078       0.001072       0.001056       0.001043   
3  ...       0.001198       0.001176       0.001124       0.001077   
4  ...       0.001201       0.001180       0.001127       0.001078   

   jl_SST_D47_SE  ag_SST_D47_SE  sp_SST_D47_SE  ot_SST_D47_SE  nv_SST_D47_SE  \
0       0.001043       0.001047       0.001044       0.001041       0.001046   
1       0.001042       0.001045       0.001043       0.001041       0.001047   
2       0.001042       0.001044       0.001043       0.001041       0.001049   
3       0.001053       0.001046       0.001049       0.001062       0.001096   
4       0.001054       0.001046       0.001049       0.001063       0.001098   

   dc_SST_D47_SE  
0       0.001059  
1       0.001062  
2       0.001065  
3       0.001144  
4       0.001144  

[5 rows x 24 columns]

For new HadCM model with 1x perindustrial pCO2¶

In [23]:
# Convert temperature data for the HadCM model with 1x pre-industrial CO2
# Identify the SAT and SST columns
SAT_HadCM_new_1PIC_columns = [col for col in Lutetian_HadCM_new_1PIC_model.columns if col.endswith('_SAT')]
SST_HadCM_new_1PIC_columns = [col for col in Lutetian_HadCM_new_1PIC_model.columns if col.endswith('_SST')]

# Apply the conversion function to the SAT columns and add new columns for D47 and D47_SE
for col in SAT_HadCM_new_1PIC_columns:
    base_col_name = col.replace('_SAT', '') # Remove the '_SAT' suffix from the column name
    Lutetian_HadCM_new_1PIC_model[f'{base_col_name}_SAT_D47'], Lutetian_HadCM_new_1PIC_model[f'{base_col_name}_SAT_D47_SE'] = zip(*Lutetian_HadCM_new_1PIC_model[col].apply(
        lambda x: D47c.OGLS23.T47(T = x) if not pd.isna(x) else (np.nan, np.nan)
    )) # Use zip() to unpack the tuple returned by the apply() method and apply the T47()-function to each value in the column
for col in SST_HadCM_new_1PIC_columns:
    base_col_name = col.replace('_SST', '') # Remove the '_SST' suffix from the column name
    Lutetian_HadCM_new_1PIC_model[f'{base_col_name}_SST_D47'], Lutetian_HadCM_new_1PIC_model[f'{base_col_name}_SST_D47_SE'] = zip(*Lutetian_HadCM_new_1PIC_model[col].apply(
        lambda x: D47c.OGLS23.T47(T = x) if not pd.isna(x) else (np.nan, np.nan)
    )) # Use zip() to unpack the tuple returned by the apply() method and apply the T47()-function to each value in the column

# Display the combined data with D47 and D47_SE columns
D47_HadCM_new_1PIC_columns = [col for col in Lutetian_HadCM_new_1PIC_model.columns if col.endswith('_D47')]
D47_se_HadCM_new_1PIC_columns = [col for col in Lutetian_HadCM_new_1PIC_model.columns if '_D47_SE' in col]
print("D47 values for all HadCM model 1x preindustrial pCO2 outcomes:\n", Lutetian_HadCM_new_1PIC_model[D47_HadCM_new_1PIC_columns].head())
print("Calibration standard errors for all HadCM model 1x preindustrial pCO2 outcomes:\n", Lutetian_HadCM_new_1PIC_model[D47_se_HadCM_new_1PIC_columns].head())
D47 values for all HadCM model 1x preindustrial pCO2 outcomes:
    ja_SAT_D47  fb_SAT_D47  mr_SAT_D47  ar_SAT_D47  my_SAT_D47  jn_SAT_D47  \
0    0.649314    0.649532    0.646869    0.641098    0.628628    0.610383   
1    0.658490    0.658851    0.655685    0.648325    0.632660    0.612362   
2    0.658868    0.660437    0.658268    0.651957    0.637527    0.617463   
3    0.636562    0.636475    0.634153    0.630067    0.620324    0.603579   
4    0.666775    0.659229    0.648746    0.638734    0.622393    0.606125   

   jl_SAT_D47  ag_SAT_D47  sp_SAT_D47  ot_SAT_D47  ...  mr_SST_D47  \
0    0.595958    0.593060    0.601917    0.618248  ...    0.619820   
1    0.598398    0.595278    0.604859    0.623366  ...    0.619261   
2    0.601347    0.596689    0.605561    0.623072  ...    0.628556   
3    0.592075    0.590043    0.596164    0.609700  ...    0.619637   
4    0.598998    0.598137    0.607167    0.626313  ...    0.623051   

   ar_SST_D47  my_SST_D47  jn_SST_D47  jl_SST_D47  ag_SST_D47  sp_SST_D47  \
0    0.618037    0.611175    0.598163    0.590329    0.588308    0.589935   
1    0.617859    0.611340    0.598414    0.590667    0.588558    0.589996   
2    0.625196    0.615527    0.600662    0.591871    0.589428    0.591714   
3    0.618953    0.613694    0.599588    0.589134    0.586816    0.590283   
4    0.622063    0.615181    0.599878    0.589858    0.587718    0.591252   

   ot_SST_D47  nv_SST_D47  dc_SST_D47  
0    0.598029    0.607598    0.614320  
1    0.597608    0.606624    0.613628  
2    0.600532    0.610380    0.618991  
3    0.598287    0.606764    0.612609  
4    0.599551    0.609201    0.615761  

[5 rows x 24 columns]
Calibration standard errors for all HadCM model 1x preindustrial pCO2 outcomes:
    ja_SAT_D47_SE  fb_SAT_D47_SE  mr_SAT_D47_SE  ar_SAT_D47_SE  my_SAT_D47_SE  \
0       0.001335       0.001337       0.001317       0.001274       0.001193   
1       0.001410       0.001413       0.001387       0.001328       0.001218   
2       0.001413       0.001427       0.001408       0.001356       0.001250   
3       0.001243       0.001243       0.001227       0.001202       0.001148   
4       0.001483       0.001416       0.001331       0.001258       0.001159   

   jn_SAT_D47_SE  jl_SAT_D47_SE  ag_SAT_D47_SE  sp_SAT_D47_SE  ot_SAT_D47_SE  \
0       0.001104       0.001060       0.001054       0.001075       0.001138   
1       0.001112       0.001066       0.001059       0.001084       0.001164   
2       0.001134       0.001074       0.001062       0.001086       0.001162   
3       0.001080       0.001053       0.001050       0.001061       0.001101   
4       0.001088       0.001067       0.001065       0.001092       0.001180   

   ...  mr_SST_D47_SE  ar_SST_D47_SE  my_SST_D47_SE  jn_SST_D47_SE  \
0  ...       0.001146       0.001137       0.001107       0.001065   
1  ...       0.001143       0.001136       0.001108       0.001066   
2  ...       0.001193       0.001174       0.001125       0.001072   
3  ...       0.001145       0.001141       0.001117       0.001069   
4  ...       0.001162       0.001157       0.001124       0.001070   

   jl_SST_D47_SE  ag_SST_D47_SE  sp_SST_D47_SE  ot_SST_D47_SE  nv_SST_D47_SE  \
0       0.001050       0.001047       0.001049       0.001065       0.001093   
1       0.001050       0.001048       0.001050       0.001064       0.001090   
2       0.001052       0.001049       0.001052       0.001071       0.001104   
3       0.001048       0.001046       0.001050       0.001066       0.001091   
4       0.001049       0.001047       0.001051       0.001069       0.001099   

   dc_SST_D47_SE  
0       0.001120  
1       0.001117  
2       0.001142  
3       0.001113  
4       0.001126  

[5 rows x 24 columns]

For new HadCM model with 2x perindustrial pCO2¶

In [24]:
# Convert temperature data for the HadCM model with 2x pre-industrial CO2
# Identify the SAT and SST columns
SAT_HadCM_new_2PIC_columns = [col for col in Lutetian_HadCM_new_2PIC_model.columns if col.endswith('_SAT')]
SST_HadCM_new_2PIC_columns = [col for col in Lutetian_HadCM_new_2PIC_model.columns if col.endswith('_SST')]

# Apply the conversion function to the SAT columns and add new columns for D47 and D47_SE
for col in SAT_HadCM_new_2PIC_columns:
    base_col_name = col.replace('_SAT', '') # Remove the '_SAT' suffix from the column name
    Lutetian_HadCM_new_2PIC_model[f'{base_col_name}_SAT_D47'], Lutetian_HadCM_new_2PIC_model[f'{base_col_name}_SAT_D47_SE'] = zip(*Lutetian_HadCM_new_2PIC_model[col].apply(
        lambda x: D47c.OGLS23.T47(T = x) if not pd.isna(x) else (np.nan, np.nan)
    )) # Use zip() to unpack the tuple returned by the apply() method and apply the T47()-function to each value in the column
for col in SST_HadCM_new_2PIC_columns:
    base_col_name = col.replace('_SST', '') # Remove the '_SST' suffix from the column name
    Lutetian_HadCM_new_2PIC_model[f'{base_col_name}_SST_D47'], Lutetian_HadCM_new_2PIC_model[f'{base_col_name}_SST_D47_SE'] = zip(*Lutetian_HadCM_new_2PIC_model[col].apply(
        lambda x: D47c.OGLS23.T47(T = x) if not pd.isna(x) else (np.nan, np.nan)
    )) # Use zip() to unpack the tuple returned by the apply() method and apply the T47()-function to each value in the column

# Display the combined data with D47 and D47_SE columns
D47_HadCM_new_2PIC_columns = [col for col in Lutetian_HadCM_new_2PIC_model.columns if col.endswith('_D47')]
D47_se_HadCM_new_2PIC_columns = [col for col in Lutetian_HadCM_new_2PIC_model.columns if '_D47_SE' in col]
print("D47 values for all HadCM model 2x preindustrial pCO2 outcomes:\n", Lutetian_HadCM_new_2PIC_model[D47_HadCM_new_2PIC_columns].head())
print("Calibration standard errors for all HadCM model 2x preindustrial pCO2 outcomes:\n", Lutetian_HadCM_new_2PIC_model[D47_se_HadCM_new_2PIC_columns].head())
D47 values for all HadCM model 2x preindustrial pCO2 outcomes:
    ja_SAT_D47  fb_SAT_D47  mr_SAT_D47  ar_SAT_D47  my_SAT_D47  jn_SAT_D47  \
0    0.635263    0.636188    0.633511    0.628476    0.616460    0.599641   
1    0.642249    0.643730    0.640365    0.634105    0.619013    0.599103   
2    0.642214    0.644917    0.642775    0.637497    0.623075    0.602602   
3    0.624396    0.625315    0.622902    0.619219    0.609535    0.593964   
4    0.650031    0.646115    0.635630    0.626910    0.611551    0.596251   

   jl_SAT_D47  ag_SAT_D47  sp_SAT_D47  ot_SAT_D47  ...  mr_SST_D47  \
0    0.586221    0.583641    0.591666    0.605627  ...    0.611563   
1    0.587329    0.585721    0.594725    0.610488  ...    0.610890   
2    0.589389    0.587108    0.595950    0.610777  ...    0.618880   
3    0.583649    0.581971    0.587516    0.598996  ...    0.611383   
4    0.589929    0.589576    0.598179    0.614516  ...    0.614333   

   ar_SST_D47  my_SST_D47  jn_SST_D47  jl_SST_D47  ag_SST_D47  sp_SST_D47  \
0    0.609661    0.603153    0.591553    0.584571    0.582125    0.583000   
1    0.609423    0.603150    0.591251    0.584502    0.582306    0.583049   
2    0.615656    0.606011    0.592279    0.585107    0.582909    0.584535   
3    0.610592    0.605196    0.592472    0.582463    0.579974    0.582705   
4    0.612994    0.605889    0.591694    0.582842    0.580932    0.583752   

   ot_SST_D47  nv_SST_D47  dc_SST_D47  
0    0.590649    0.600020    0.606596  
1    0.590448    0.599235    0.605800  
2    0.592975    0.602354    0.610318  
3    0.590459    0.598792    0.604624  
4    0.591868    0.601060    0.607322  

[5 rows x 24 columns]
Calibration standard errors for all HadCM model 2x preindustrial pCO2 outcomes:
    ja_SAT_D47_SE  fb_SAT_D47_SE  mr_SAT_D47_SE  ar_SAT_D47_SE  my_SAT_D47_SE  \
0       0.001235       0.001241       0.001223       0.001192       0.001130   
1       0.001283       0.001293       0.001269       0.001227       0.001142   
2       0.001282       0.001302       0.001286       0.001249       0.001162   
3       0.001169       0.001174       0.001161       0.001143       0.001101   
4       0.001341       0.001311       0.001237       0.001183       0.001108   

   jn_SAT_D47_SE  jl_SAT_D47_SE  ag_SAT_D47_SE  sp_SAT_D47_SE  ot_SAT_D47_SE  \
0       0.001069       0.001045       0.001043       0.001052       0.001087   
1       0.001068       0.001046       0.001044       0.001058       0.001104   
2       0.001077       0.001049       0.001046       0.001060       0.001105   
3       0.001056       0.001043       0.001042       0.001046       0.001067   
4       0.001061       0.001049       0.001049       0.001065       0.001121   

   ...  mr_SST_D47_SE  ar_SST_D47_SE  my_SST_D47_SE  jn_SST_D47_SE  \
0  ...       0.001109       0.001101       0.001079       0.001052   
1  ...       0.001106       0.001100       0.001079       0.001051   
2  ...       0.001141       0.001126       0.001088       0.001053   
3  ...       0.001108       0.001105       0.001085       0.001053   
4  ...       0.001120       0.001114       0.001088       0.001052   

   jl_SST_D47_SE  ag_SST_D47_SE  sp_SST_D47_SE  ot_SST_D47_SE  nv_SST_D47_SE  \
0       0.001044       0.001042       0.001042       0.001050       0.001070   
1       0.001043       0.001042       0.001042       0.001050       0.001068   
2       0.001044       0.001042       0.001043       0.001054       0.001076   
3       0.001042       0.001041       0.001042       0.001050       0.001067   
4       0.001042       0.001041       0.001043       0.001052       0.001073   

   dc_SST_D47_SE  
0       0.001090  
1       0.001087  
2       0.001104  
3       0.001083  
4       0.001093  

[5 rows x 24 columns]

For new HadCM model with 1056 ppm pCO2¶

In [25]:
# Convert temperature data for the HadCM model with 1056 ppm CO2
# Identify the SAT and SST columns
SAT_HadCM_new_1056ppm_columns = [col for col in Lutetian_HadCM_new_1056ppm_model.columns if col.endswith('_SAT')]
SST_HadCM_new_1056ppm_columns = [col for col in Lutetian_HadCM_new_1056ppm_model.columns if col.endswith('_SST')]

# Apply the conversion function to the SAT columns and add new columns for D47 and D47_SE
for col in SAT_HadCM_new_1056ppm_columns:
    base_col_name = col.replace('_SAT', '') # Remove the '_SAT' suffix from the column name
    Lutetian_HadCM_new_1056ppm_model[f'{base_col_name}_SAT_D47'], Lutetian_HadCM_new_1056ppm_model[f'{base_col_name}_SAT_D47_SE'] = zip(*Lutetian_HadCM_new_1056ppm_model[col].apply(
        lambda x: D47c.OGLS23.T47(T = x) if not pd.isna(x) else (np.nan, np.nan)
    )) # Use zip() to unpack the tuple returned by the apply() method and apply the T47()-function to each value in the column
for col in SST_HadCM_new_1056ppm_columns:
    base_col_name = col.replace('_SST', '') # Remove the '_SST' suffix from the column name
    Lutetian_HadCM_new_1056ppm_model[f'{base_col_name}_SST_D47'], Lutetian_HadCM_new_1056ppm_model[f'{base_col_name}_SST_D47_SE'] = zip(*Lutetian_HadCM_new_1056ppm_model[col].apply(
        lambda x: D47c.OGLS23.T47(T = x) if not pd.isna(x) else (np.nan, np.nan)
    )) # Use zip() to unpack the tuple returned by the apply() method and apply the T47()-function to each value in the column

# Display the combined data with D47 and D47_SE columns
D47_HadCM_new_1056ppm_columns = [col for col in Lutetian_HadCM_new_1056ppm_model.columns if col.endswith('_D47')]
D47_se_HadCM_new_1056ppm_columns = [col for col in Lutetian_HadCM_new_1056ppm_model.columns if '_D47_SE' in col]
print("D47 values for all HadCM model 1056 ppm pCO2 outcomes:\n", Lutetian_HadCM_new_1056ppm_model[D47_HadCM_new_1056ppm_columns].head())
print("Calibration standard errors for all HadCM model 1056 ppm pCO2 outcomes:\n", Lutetian_HadCM_new_1056ppm_model[D47_se_HadCM_new_1056ppm_columns].head())
D47 values for all HadCM model 1056 ppm pCO2 outcomes:
    ja_SAT_D47  fb_SAT_D47  mr_SAT_D47  ar_SAT_D47  my_SAT_D47  jn_SAT_D47  \
0    0.625999    0.626866    0.625237    0.619942    0.608866    0.592780   
1    0.631948    0.632783    0.631225    0.624299    0.610803    0.591568   
2    0.631501    0.633310    0.633035    0.627377    0.614579    0.594306   
3    0.615905    0.616517    0.615368    0.611138    0.602291    0.587788   
4    0.638832    0.633538    0.627128    0.616879    0.603802    0.588733   

   jl_SAT_D47  ag_SAT_D47  sp_SAT_D47  ot_SAT_D47  ...  mr_SST_D47  \
0    0.579672    0.576946    0.584411    0.597488  ...    0.605123   
1    0.579762    0.578541    0.586737    0.601736  ...    0.604587   
2    0.581854    0.580169    0.588095    0.601666  ...    0.611901   
3    0.577532    0.575583    0.580775    0.591800  ...    0.604890   
4    0.580942    0.581502    0.589338    0.605672  ...    0.607587   

   ar_SST_D47  my_SST_D47  jn_SST_D47  jl_SST_D47  ag_SST_D47  sp_SST_D47  \
0    0.603131    0.597247    0.587153    0.580623    0.577211    0.577595   
1    0.603123    0.597526    0.586721    0.579954    0.576934    0.577456   
2    0.608641    0.600078    0.587311    0.580162    0.577275    0.578731   
3    0.604036    0.598871    0.587694    0.578456    0.574712    0.577089   
4    0.606307    0.599742    0.587023    0.578345    0.575325    0.577753   

   ot_SST_D47  nv_SST_D47  dc_SST_D47  
0    0.584750    0.594385    0.600574  
1    0.584307    0.593765    0.599964  
2    0.586423    0.596758    0.604276  
3    0.584295    0.592687    0.598288  
4    0.585403    0.595043    0.600976  

[5 rows x 24 columns]
Calibration standard errors for all HadCM model 1056 ppm pCO2 outcomes:
    ja_SAT_D47_SE  fb_SAT_D47_SE  mr_SAT_D47_SE  ar_SAT_D47_SE  my_SAT_D47_SE  \
0       0.001178       0.001183       0.001174       0.001146       0.001098   
1       0.001213       0.001219       0.001209       0.001169       0.001105   
2       0.001211       0.001222       0.001220       0.001186       0.001121   
3       0.001127       0.001130       0.001125       0.001107       0.001076   
4       0.001259       0.001223       0.001185       0.001132       0.001081   

   jn_SAT_D47_SE  jl_SAT_D47_SE  ag_SAT_D47_SE  sp_SAT_D47_SE  ot_SAT_D47_SE  \
0       0.001054       0.001041       0.001041       0.001043       0.001064   
1       0.001052       0.001041       0.001041       0.001045       0.001075   
2       0.001057       0.001042       0.001041       0.001047       0.001074   
3       0.001047       0.001041       0.001041       0.001041       0.001052   
4       0.001048       0.001041       0.001042       0.001049       0.001087   

   ...  mr_SST_D47_SE  ar_SST_D47_SE  my_SST_D47_SE  jn_SST_D47_SE  \
0  ...       0.001085       0.001079       0.001063       0.001046   
1  ...       0.001083       0.001079       0.001064       0.001045   
2  ...       0.001110       0.001097       0.001070       0.001046   
3  ...       0.001084       0.001082       0.001067       0.001047   
4  ...       0.001093       0.001089       0.001069       0.001046   

   jl_SST_D47_SE  ag_SST_D47_SE  sp_SST_D47_SE  ot_SST_D47_SE  nv_SST_D47_SE  \
0       0.001041       0.001041       0.001041       0.001044       0.001057   
1       0.001041       0.001041       0.001041       0.001043       0.001056   
2       0.001041       0.001041       0.001041       0.001045       0.001062   
3       0.001041       0.001042       0.001041       0.001043       0.001054   
4       0.001041       0.001041       0.001041       0.001044       0.001058   

   dc_SST_D47_SE  
0       0.001071  
1       0.001070  
2       0.001082  
3       0.001066  
4       0.001073  

[5 rows x 24 columns]

For old HadCM model with 2x perindustrial pCO2¶

In [26]:
# Convert temperature data for the old HadCM model with 2x pre-industrial CO2
# Identify the SAT and SST columns
SAT_HadCM_old_2PIC_columns = [col for col in Lutetian_HadCM_old_2PIC_model.columns if col.endswith('_SAT')]
SST_HadCM_old_2PIC_columns = [col for col in Lutetian_HadCM_old_2PIC_model.columns if col.endswith('_SST')]

# Apply the conversion function to the SAT columns and add new columns for D47 and D47_SE
for col in SAT_HadCM_old_2PIC_columns:
    base_col_name = col.replace('_SAT', '') # Remove the '_SAT' suffix from the column name
    Lutetian_HadCM_old_2PIC_model[f'{base_col_name}_SAT_D47'], Lutetian_HadCM_old_2PIC_model[f'{base_col_name}_SAT_D47_SE'] = zip(*Lutetian_HadCM_old_2PIC_model[col].apply(
        lambda x: D47c.OGLS23.T47(T = x) if not pd.isna(x) else (np.nan, np.nan)
    )) # Use zip() to unpack the tuple returned by the apply() method and apply the T47()-function to each value in the column
for col in SST_HadCM_old_2PIC_columns:
    base_col_name = col.replace('_SST', '') # Remove the '_SST' suffix from the column name
    Lutetian_HadCM_old_2PIC_model[f'{base_col_name}_SST_D47'], Lutetian_HadCM_old_2PIC_model[f'{base_col_name}_SST_D47_SE'] = zip(*Lutetian_HadCM_old_2PIC_model[col].apply(
        lambda x: D47c.OGLS23.T47(T = x) if not pd.isna(x) else (np.nan, np.nan)
    )) # Use zip() to unpack the tuple returned by the apply() method and apply the T47()-function to each value in the column

# Display the combined data with D47 and D47_SE columns
D47_HadCM_old_2PIC_columns = [col for col in Lutetian_HadCM_old_2PIC_model.columns if col.endswith('_D47')]
D47_se_HadCM_old_2PIC_columns = [col for col in Lutetian_HadCM_old_2PIC_model.columns if '_D47_SE' in col]
print("D47 values for all old HadCM model 2x preindustrial pCO2 outcomes:\n", Lutetian_HadCM_old_2PIC_model[D47_HadCM_old_2PIC_columns].head())
print("Calibration standard errors for all old HadCM model 2x preindustrial pCO2 outcomes:\n", Lutetian_HadCM_old_2PIC_model[D47_se_HadCM_old_2PIC_columns].head())
D47 values for all old HadCM model 2x preindustrial pCO2 outcomes:
    ja_SAT_D47  fb_SAT_D47  mr_SAT_D47  ar_SAT_D47  my_SAT_D47  jn_SAT_D47  \
0    0.621479    0.621749    0.619999    0.615386    0.606099    0.594473   
1    0.626878    0.626964    0.624847    0.619754    0.608017    0.593061   
2    0.627793    0.629021    0.627793    0.622599    0.610761    0.594346   
3    0.612452    0.613220    0.612154    0.608198    0.599813    0.588684   
4    0.642211    0.635149    0.624440    0.612316    0.598682    0.582807   

   jl_SAT_D47  ag_SAT_D47  sp_SAT_D47  ot_SAT_D47  ...  mr_SST_D47  \
0    0.583127    0.576368    0.580028    0.592956  ...    0.604433   
1    0.581541    0.575316    0.580263    0.595627  ...    0.604986   
2    0.581769    0.576907    0.582607    0.596563  ...    0.607415   
3    0.579127    0.574798    0.577224    0.587470  ...    0.606422   
4    0.575847    0.575000    0.585403    0.603424  ...    0.608445   

   ar_SST_D47  my_SST_D47  jn_SST_D47  jl_SST_D47  ag_SST_D47  sp_SST_D47  \
0    0.601636    0.594606    0.584886    0.579352    0.576142    0.575630   
1    0.602297    0.594689    0.583945    0.578157    0.575023    0.574856   
2    0.603910    0.594881    0.583445    0.578165    0.575373    0.575115   
3    0.603856    0.596232    0.585046    0.577843    0.574394    0.575516   
4    0.605995    0.598629    0.587366    0.579447    0.575822    0.576716   

   ot_SST_D47  nv_SST_D47  dc_SST_D47  
0    0.581670    0.590809    0.598345  
1    0.581191    0.590222    0.598174  
2    0.582326    0.591776    0.600193  
3    0.583441    0.593301    0.600655  
4    0.585471    0.595260    0.602927  

[5 rows x 24 columns]
Calibration standard errors for all old HadCM model 2x preindustrial pCO2 outcomes:
    ja_SAT_D47_SE  fb_SAT_D47_SE  mr_SAT_D47_SE  ar_SAT_D47_SE  my_SAT_D47_SE  \
0       0.001154       0.001155       0.001146       0.001125       0.001088   
1       0.001183       0.001184       0.001172       0.001145       0.001095   
2       0.001188       0.001196       0.001188       0.001160       0.001105   
3       0.001112       0.001115       0.001111       0.001096       0.001069   
4       0.001282       0.001234       0.001170       0.001112       0.001067   

   jn_SAT_D47_SE  jl_SAT_D47_SE  ag_SAT_D47_SE  sp_SAT_D47_SE  ot_SAT_D47_SE  \
0       0.001057       0.001043       0.001041       0.001041       0.001054   
1       0.001054       0.001042       0.001041       0.001041       0.001059   
2       0.001057       0.001042       0.001041       0.001042       0.001062   
3       0.001048       0.001041       0.001042       0.001041       0.001046   
4       0.001042       0.001041       0.001041       0.001044       0.001080   

   ...  mr_SST_D47_SE  ar_SST_D47_SE  my_SST_D47_SE  jn_SST_D47_SE  \
0  ...       0.001083       0.001074       0.001057       0.001044   
1  ...       0.001085       0.001076       0.001058       0.001043   
2  ...       0.001093       0.001081       0.001058       0.001043   
3  ...       0.001089       0.001081       0.001061       0.001044   
4  ...       0.001097       0.001088       0.001066       0.001046   

   jl_SST_D47_SE  ag_SST_D47_SE  sp_SST_D47_SE  ot_SST_D47_SE  nv_SST_D47_SE  \
0       0.001041       0.001041       0.001041       0.001042       0.001051   
1       0.001041       0.001041       0.001042       0.001042       0.001050   
2       0.001041       0.001041       0.001041       0.001042       0.001052   
3       0.001041       0.001042       0.001041       0.001043       0.001055   
4       0.001041       0.001041       0.001041       0.001044       0.001059   

   dc_SST_D47_SE  
0       0.001066  
1       0.001065  
2       0.001070  
3       0.001072  
4       0.001078  

[5 rows x 24 columns]

For old HadCM model with 4x perindustrial pCO2¶

In [27]:
# Convert temperature data for the old HadCM model with 4x pre-industrial CO2
# Identify the SAT and SST columns
SAT_HadCM_old_4PIC_columns = [col for col in Lutetian_HadCM_old_4PIC_model.columns if col.endswith('_SAT')]
SST_HadCM_old_4PIC_columns = [col for col in Lutetian_HadCM_old_4PIC_model.columns if col.endswith('_SST')]

# Apply the conversion function to the SAT columns and add new columns for D47 and D47_SE
for col in SAT_HadCM_old_4PIC_columns:
    base_col_name = col.replace('_SAT', '') # Remove the '_SAT' suffix from the column name
    Lutetian_HadCM_old_4PIC_model[f'{base_col_name}_SAT_D47'], Lutetian_HadCM_old_4PIC_model[f'{base_col_name}_SAT_D47_SE'] = zip(*Lutetian_HadCM_old_4PIC_model[col].apply(
        lambda x: D47c.OGLS23.T47(T = x) if not pd.isna(x) else (np.nan, np.nan)
    )) # Use zip() to unpack the tuple returned by the apply() method and apply the T47()-function to each value in the column
for col in SST_HadCM_old_4PIC_columns:
    base_col_name = col.replace('_SST', '') # Remove the '_SST' suffix from the column name
    Lutetian_HadCM_old_4PIC_model[f'{base_col_name}_SST_D47'], Lutetian_HadCM_old_4PIC_model[f'{base_col_name}_SST_D47_SE'] = zip(*Lutetian_HadCM_old_4PIC_model[col].apply(
        lambda x: D47c.OGLS23.T47(T = x) if not pd.isna(x) else (np.nan, np.nan)
    )) # Use zip() to unpack the tuple returned by the apply() method and apply the T47()-function to each value in the column

# Display the combined data with D47 and D47_SE columns
D47_HadCM_old_4PIC_columns = [col for col in Lutetian_HadCM_old_4PIC_model.columns if col.endswith('_D47')]
D47_se_HadCM_old_4PIC_columns = [col for col in Lutetian_HadCM_old_4PIC_model.columns if '_D47_SE' in col]
print("D47 values for all old HadCM model 4x preindustrial pCO2 outcomes:\n", Lutetian_HadCM_old_4PIC_model[D47_HadCM_old_4PIC_columns].head())
print("Calibration standard errors for all old HadCM model 4x preindustrial pCO2 outcomes:\n", Lutetian_HadCM_old_4PIC_model[D47_se_HadCM_old_4PIC_columns].head())
D47 values for all old HadCM model 4x preindustrial pCO2 outcomes:
    ja_SAT_D47  fb_SAT_D47  mr_SAT_D47  ar_SAT_D47  my_SAT_D47  jn_SAT_D47  \
0    0.621479    0.621749    0.619999    0.615386    0.606099    0.594473   
1    0.626878    0.626964    0.624847    0.619754    0.608017    0.593061   
2    0.627793    0.629021    0.627793    0.622599    0.610761    0.594346   
3    0.612452    0.613220    0.612154    0.608198    0.599813    0.588684   
4    0.642211    0.635149    0.624440    0.612316    0.598682    0.582807   

   jl_SAT_D47  ag_SAT_D47  sp_SAT_D47  ot_SAT_D47  ...  mr_SST_D47  \
0    0.583127    0.576368    0.580028    0.592956  ...    0.604433   
1    0.581541    0.575316    0.580263    0.595627  ...    0.604986   
2    0.581769    0.576907    0.582607    0.596563  ...    0.607415   
3    0.579127    0.574798    0.577224    0.587470  ...    0.606422   
4    0.575847    0.575000    0.585403    0.603424  ...    0.608445   

   ar_SST_D47  my_SST_D47  jn_SST_D47  jl_SST_D47  ag_SST_D47  sp_SST_D47  \
0    0.601636    0.594606    0.584886    0.579352    0.576142    0.575630   
1    0.602297    0.594689    0.583945    0.578157    0.575023    0.574856   
2    0.603910    0.594881    0.583445    0.578165    0.575373    0.575115   
3    0.603856    0.596232    0.585046    0.577843    0.574394    0.575516   
4    0.605995    0.598629    0.587366    0.579447    0.575822    0.576716   

   ot_SST_D47  nv_SST_D47  dc_SST_D47  
0    0.581670    0.590809    0.598345  
1    0.581191    0.590222    0.598174  
2    0.582326    0.591776    0.600193  
3    0.583441    0.593301    0.600655  
4    0.585471    0.595260    0.602927  

[5 rows x 24 columns]
Calibration standard errors for all old HadCM model 4x preindustrial pCO2 outcomes:
    ja_SAT_D47_SE  fb_SAT_D47_SE  mr_SAT_D47_SE  ar_SAT_D47_SE  my_SAT_D47_SE  \
0       0.001154       0.001155       0.001146       0.001125       0.001088   
1       0.001183       0.001184       0.001172       0.001145       0.001095   
2       0.001188       0.001196       0.001188       0.001160       0.001105   
3       0.001112       0.001115       0.001111       0.001096       0.001069   
4       0.001282       0.001234       0.001170       0.001112       0.001067   

   jn_SAT_D47_SE  jl_SAT_D47_SE  ag_SAT_D47_SE  sp_SAT_D47_SE  ot_SAT_D47_SE  \
0       0.001057       0.001043       0.001041       0.001041       0.001054   
1       0.001054       0.001042       0.001041       0.001041       0.001059   
2       0.001057       0.001042       0.001041       0.001042       0.001062   
3       0.001048       0.001041       0.001042       0.001041       0.001046   
4       0.001042       0.001041       0.001041       0.001044       0.001080   

   ...  mr_SST_D47_SE  ar_SST_D47_SE  my_SST_D47_SE  jn_SST_D47_SE  \
0  ...       0.001083       0.001074       0.001057       0.001044   
1  ...       0.001085       0.001076       0.001058       0.001043   
2  ...       0.001093       0.001081       0.001058       0.001043   
3  ...       0.001089       0.001081       0.001061       0.001044   
4  ...       0.001097       0.001088       0.001066       0.001046   

   jl_SST_D47_SE  ag_SST_D47_SE  sp_SST_D47_SE  ot_SST_D47_SE  nv_SST_D47_SE  \
0       0.001041       0.001041       0.001041       0.001042       0.001051   
1       0.001041       0.001041       0.001042       0.001042       0.001050   
2       0.001041       0.001041       0.001041       0.001042       0.001052   
3       0.001041       0.001042       0.001041       0.001043       0.001055   
4       0.001041       0.001041       0.001041       0.001044       0.001059   

   dc_SST_D47_SE  
0       0.001066  
1       0.001065  
2       0.001070  
3       0.001072  
4       0.001078  

[5 rows x 24 columns]

Estimate seawater oxygen isotope value from salinity based on modern North Sea d18Ow-salinity relationship by Harwood et al. (2007)¶

For CESM with 4x perindustrial pCO2¶

In [28]:
# Apply the d18Ow-SSS function from Harwood et al. (2007) to all SSS columns

# First for the CESM model with 4x pre-industrial CO2
# Identify the SSS columns
SSS_CESM_4PIC_columns = [col for col in Lutetian_CESM_4PIC_model.columns if col.endswith('_SSS')]

# Apply the conversion function to the SSS columns and add new columns for d18Ow and d18Ow_SE
for col in SSS_CESM_4PIC_columns:
    base_col_name = col.replace('_SSS', '')  # Remove the '_SSS' suffix from the column name
    Lutetian_CESM_4PIC_model[f'{base_col_name}_SSS_d18Ow'] = Lutetian_CESM_4PIC_model[col].apply(
        lambda x: -9.300 + 0.274 * x if not pd.isna(x) else np.nan  # Calculate d18Ow
    )

# Display the combined data with d18Ow and d18Ow_SE columns
d18Ow_CESM_4PIC_columns = [col for col in Lutetian_CESM_4PIC_model.columns if col.endswith('_d18Ow')]
print("d18Ow values for all model outcomes:\n", Lutetian_CESM_4PIC_model[d18Ow_CESM_4PIC_columns].head())
d18Ow values for all model outcomes:
    ja_SSS_d18Ow  fb_SSS_d18Ow  mr_SSS_d18Ow  ar_SSS_d18Ow  my_SSS_d18Ow  \
0      0.412163      0.417397      0.416426      0.420510      0.427636   
1      0.412551      0.419215      0.420105      0.424757      0.431978   
2      0.391470      0.397124      0.397364      0.401573      0.409009   
3     -1.716298     -1.696593     -1.699113     -1.718610     -1.746921   
4     -1.724499     -1.705170     -1.711377     -1.735129     -1.771551   

   jn_SSS_d18Ow  jl_SSS_d18Ow  ag_SSS_d18Ow  sp_SSS_d18Ow  ot_SSS_d18Ow  \
0      0.433800      0.432326      0.418661      0.386762      0.361828   
1      0.436819      0.435099      0.426873      0.402075      0.378333   
2      0.412444      0.409529      0.403192      0.382842      0.365661   
3     -1.771086     -1.798713     -1.820124     -1.836465     -1.833743   
4     -1.802794     -1.832529     -1.854027     -1.869227     -1.862037   

   nv_SSS_d18Ow  dc_SSS_d18Ow  
0      0.371852      0.395830  
1      0.379386      0.397893  
2      0.365822      0.380555  
3     -1.797647     -1.748480  
4     -1.814293     -1.760033  

For CESM with 2x perindustrial pCO2¶

In [29]:
# Calculate d18Ow for the CESM model with 2x pre-industrial CO2
# Identify the SSS columns
SSS_CESM_2PIC_columns = [col for col in Lutetian_CESM_2PIC_model.columns if col.endswith('_SSS')]

# Apply the conversion function to the SSS columns and add new columns for d18Ow and d18Ow_SE
for col in SSS_CESM_2PIC_columns:
    base_col_name = col.replace('_SSS', '')  # Remove the '_SSS' suffix from the column name
    Lutetian_CESM_2PIC_model[f'{base_col_name}_SSS_d18Ow'] = Lutetian_CESM_2PIC_model[col].apply(
        lambda x: -9.300 + 0.274 * x if not pd.isna(x) else np.nan  # Calculate d18Ow
    )

# Display the combined data with d18Ow and d18Ow_SE columns
d18Ow_CESM_2PIC_columns = [col for col in Lutetian_CESM_2PIC_model.columns if col.endswith('_d18Ow')]
print("d18Ow values for all model outcomes:\n", Lutetian_CESM_2PIC_model[d18Ow_CESM_2PIC_columns].head())
d18Ow values for all model outcomes:
    ja_SSS_d18Ow  fb_SSS_d18Ow  mr_SSS_d18Ow  ar_SSS_d18Ow  my_SSS_d18Ow  \
0      0.457617      0.449562      0.442842      0.440457      0.448478   
1      0.455972      0.451012      0.445746      0.443246      0.448766   
2      0.433992      0.429306      0.423751      0.420202      0.423995   
3     -1.600125     -1.587918     -1.593103     -1.623087     -1.663342   
4     -1.604723     -1.595348     -1.603947     -1.641113     -1.687715   

   jn_SSS_d18Ow  jl_SSS_d18Ow  ag_SSS_d18Ow  sp_SSS_d18Ow  ot_SSS_d18Ow  \
0      0.455517      0.457858      0.451676      0.438730      0.432616   
1      0.453875      0.455338      0.453152      0.446492      0.440568   
2      0.426841      0.425764      0.424374      0.423545      0.422326   
3     -1.691195     -1.716381     -1.737248     -1.747069     -1.739627   
4     -1.720774     -1.747673     -1.767869     -1.776518     -1.764211   

   nv_SSS_d18Ow  dc_SSS_d18Ow  
0      0.444299      0.456633  
1      0.446245      0.454761  
2      0.428876      0.435168  
3     -1.698605     -1.638065  
4     -1.709789     -1.641279  

For new HadCM model with 1x perindustrial pCO2¶

In [30]:
# Calculate d18Ow for the new HadCM model with 2x pre-industrial CO2
# Identify the SSS columns
SSS_HadCM_new_1PIC_columns = [col for col in Lutetian_HadCM_new_1PIC_model.columns if col.endswith('_SSS')]

# Apply the conversion function to the SSS columns and add new columns for d18Ow and d18Ow_SE
for col in SSS_HadCM_new_1PIC_columns:
    base_col_name = col.replace('_SSS', '')  # Remove the '_SSS' suffix from the column name
    Lutetian_HadCM_new_1PIC_model[f'{base_col_name}_SSS_d18Ow'] = Lutetian_HadCM_new_1PIC_model[col].apply(
        lambda x: -9.300 + 0.274 * x if not pd.isna(x) else np.nan  # Calculate d18Ow
    )

# Display the combined data with d18Ow and d18Ow_SE columns
d18Ow_HadCM_new_1PIC_columns = [col for col in Lutetian_HadCM_new_1PIC_model.columns if col.endswith('_d18Ow')]
print("d18Ow values for all model outcomes:\n", Lutetian_HadCM_new_1PIC_model[d18Ow_HadCM_new_1PIC_columns].head())
d18Ow values for all model outcomes:
    ja_SSS_d18Ow  fb_SSS_d18Ow  mr_SSS_d18Ow  ar_SSS_d18Ow  my_SSS_d18Ow  \
0      0.728492      0.723816      0.722658      0.723479      0.723571   
1      0.725648      0.724492      0.725863      0.728494      0.731327   
2      0.678770      0.672299      0.675349      0.681626      0.690663   
3      0.732131      0.730294      0.726656      0.725570      0.721657   
4      0.713698      0.714482      0.714582      0.716600      0.719887   

   jn_SSS_d18Ow  jl_SSS_d18Ow  ag_SSS_d18Ow  sp_SSS_d18Ow  ot_SSS_d18Ow  \
0      0.718046      0.707071      0.700301      0.712572      0.730776   
1      0.732760      0.724390      0.719080      0.727738      0.737476   
2      0.698161      0.693189      0.688407      0.698954      0.706362   
3      0.710901      0.691207      0.675716      0.688672      0.708663   
4      0.715040      0.706389      0.699770      0.708793      0.721798   

   nv_SSS_d18Ow  dc_SSS_d18Ow  
0      0.738091      0.735785  
1      0.738508      0.733766  
2      0.701069      0.690490  
3      0.721718      0.728676  
4      0.716220      0.713410  

For new HadCM model with 2x perindustrial pCO2¶

In [31]:
# Calculate d18Ow for the new HadCM model with 2x pre-industrial CO2
# Identify the SSS columns
SSS_HadCM_new_2PIC_columns = [col for col in Lutetian_HadCM_new_2PIC_model.columns if col.endswith('_SSS')]

# Apply the conversion function to the SSS columns and add new columns for d18Ow and d18Ow_SE
for col in SSS_HadCM_new_2PIC_columns:
    base_col_name = col.replace('_SSS', '')  # Remove the '_SSS' suffix from the column name
    Lutetian_HadCM_new_2PIC_model[f'{base_col_name}_SSS_d18Ow'] = Lutetian_HadCM_new_2PIC_model[col].apply(
        lambda x: -9.300 + 0.274 * x if not pd.isna(x) else np.nan  # Calculate d18Ow
    )

# Display the combined data with d18Ow and d18Ow_SE columns
d18Ow_HadCM_new_2PIC_columns = [col for col in Lutetian_HadCM_new_2PIC_model.columns if col.endswith('_d18Ow')]
print("d18Ow values for all model outcomes:\n", Lutetian_HadCM_new_2PIC_model[d18Ow_HadCM_new_2PIC_columns].head())
d18Ow values for all model outcomes:
    ja_SSS_d18Ow  fb_SSS_d18Ow  mr_SSS_d18Ow  ar_SSS_d18Ow  my_SSS_d18Ow  \
0      0.811437      0.805487      0.805250      0.807841      0.803697   
1      0.806881      0.804756      0.807213      0.810979      0.811752   
2      0.758579      0.751175      0.754590      0.762000      0.771146   
3      0.815456      0.812143      0.808163      0.807469      0.799893   
4      0.794913      0.794419      0.794913      0.798267      0.798405   

   jn_SSS_d18Ow  jl_SSS_d18Ow  ag_SSS_d18Ow  sp_SSS_d18Ow  ot_SSS_d18Ow  \
0      0.800994      0.796440      0.790733      0.808524      0.823438   
1      0.816399      0.810916      0.804832      0.819014      0.826845   
2      0.779537      0.775815      0.773348      0.787377      0.791992   
3      0.791814      0.783627      0.763053      0.779218      0.797621   
4      0.793836      0.788603      0.779419      0.793240      0.806758   

   nv_SSS_d18Ow  dc_SSS_d18Ow  
0      0.827773      0.821396  
1      0.824124      0.815710  
2      0.783353      0.771397  
3      0.808397      0.813004  
4      0.800027      0.795366  

For new HadCM model with 1056 ppm pCO2¶

In [32]:
# Calculate d18Ow for the new HadCM model with 1056 ppm CO2
# Identify the SSS columns
SSS_HadCM_new_1056ppm_columns = [col for col in Lutetian_HadCM_new_1056ppm_model.columns if col.endswith('_SSS')]

# Apply the conversion function to the SSS columns and add new columns for d18Ow and d18Ow_SE
for col in SSS_HadCM_new_1056ppm_columns:
    base_col_name = col.replace('_SSS', '')  # Remove the '_SSS' suffix from the column name
    Lutetian_HadCM_new_1056ppm_model[f'{base_col_name}_SSS_d18Ow'] = Lutetian_HadCM_new_1056ppm_model[col].apply(
        lambda x: -9.300 + 0.274 * x if not pd.isna(x) else np.nan  # Calculate d18Ow
    )

# Display the combined data with d18Ow and d18Ow_SE columns
d18Ow_HadCM_new_1056ppm_columns = [col for col in Lutetian_HadCM_new_1056ppm_model.columns if col.endswith('_d18Ow')]
print("d18Ow values for all model outcomes:\n", Lutetian_HadCM_new_1056ppm_model[d18Ow_HadCM_new_1056ppm_columns].head())
d18Ow values for all model outcomes:
    ja_SSS_d18Ow  fb_SSS_d18Ow  mr_SSS_d18Ow  ar_SSS_d18Ow  my_SSS_d18Ow  \
0      0.873898      0.867618      0.867569      0.871600      0.873578   
1      0.865885      0.864033      0.865524      0.870754      0.876423   
2      0.812660      0.806048      0.809213      0.819473      0.832309   
3      0.883941      0.876824      0.872641      0.872904      0.867391   
4      0.857655      0.855579      0.854971      0.859815      0.863475   

   jn_SSS_d18Ow  jl_SSS_d18Ow  ag_SSS_d18Ow  sp_SSS_d18Ow  ot_SSS_d18Ow  \
0      0.872901      0.880796      0.893093      0.909543      0.908607   
1      0.883397      0.888450      0.895552      0.909154      0.901718   
2      0.844635      0.848587      0.854068      0.866653      0.857756   
3      0.858121      0.863630      0.867814      0.878142      0.884862   
4      0.859093      0.862812      0.870127      0.882386      0.883423   

   nv_SSS_d18Ow  dc_SSS_d18Ow  
0      0.901013      0.887231  
1      0.888703      0.875178  
2      0.841337      0.826700  
3      0.888496      0.885850  
4      0.868421      0.859741  

For old HadCM model with 2x perindustrial pCO2¶

In [33]:
# Calculate d18Ow for the old HadCM model with 2x pre-industrial CO2
# Identify the SSS columns
SSS_HadCM_old_2PIC_columns = [col for col in Lutetian_HadCM_old_2PIC_model.columns if col.endswith('_SSS')]

# Apply the conversion function to the SSS columns and add new columns for d18Ow and d18Ow_SE
for col in SSS_HadCM_old_2PIC_columns:
    base_col_name = col.replace('_SSS', '')  # Remove the '_SSS' suffix from the column name
    Lutetian_HadCM_old_2PIC_model[f'{base_col_name}_SSS_d18Ow'] = Lutetian_HadCM_old_2PIC_model[col].apply(
        lambda x: -9.300 + 0.274 * x if not pd.isna(x) else np.nan  # Calculate d18Ow
    )

# Display the combined data with d18Ow and d18Ow_SE columns
d18Ow_HadCM_old_2PIC_columns = [col for col in Lutetian_HadCM_old_2PIC_model.columns if col.endswith('_d18Ow')]
print("d18Ow values for all model outcomes:\n", Lutetian_HadCM_old_2PIC_model[d18Ow_HadCM_old_2PIC_columns].head())
d18Ow values for all model outcomes:
    ja_SSS_d18Ow  fb_SSS_d18Ow  mr_SSS_d18Ow  ar_SSS_d18Ow  my_SSS_d18Ow  \
0      2.730385      2.744889      2.747529      2.741694      2.738172   
1      2.795991      2.802639      2.805744      2.804372      2.808415   
2      2.837809      2.840615      2.840784      2.840007      2.851089   
3      2.777538      2.785695      2.791531      2.788105      2.786381   
4      2.809492      2.814421      2.818105      2.819479      2.818072   

   jn_SSS_d18Ow  jl_SSS_d18Ow  ag_SSS_d18Ow  sp_SSS_d18Ow  ot_SSS_d18Ow  \
0      2.750210      2.759200      2.772942      2.769145      2.745299   
1      2.828405      2.840431      2.852451      2.850035      2.827458   
2      2.875549      2.889367      2.895949      2.892115      2.864288   
3      2.799461      2.820661      2.842595      2.836395      2.806944   
4      2.827237      2.844929      2.866786      2.863590      2.838464   

   nv_SSS_d18Ow  dc_SSS_d18Ow  
0      2.729710      2.726179  
1      2.811291      2.800433  
2      2.849760      2.841525  
3      2.785955      2.777641  
4      2.820463      2.812720  

For old HadCM model with 4x perindustrial pCO2¶

In [34]:
# Calculate d18Ow for the old HadCM model with 4x pre-industrial CO2
# Identify the SSS columns
SSS_HadCM_old_4PIC_columns = [col for col in Lutetian_HadCM_old_4PIC_model.columns if col.endswith('_SSS')]

# Apply the conversion function to the SSS columns and add new columns for d18Ow and d18Ow_SE
for col in SSS_HadCM_old_4PIC_columns:
    base_col_name = col.replace('_SSS', '')  # Remove the '_SSS' suffix from the column name
    Lutetian_HadCM_old_4PIC_model[f'{base_col_name}_SSS_d18Ow'] = Lutetian_HadCM_old_4PIC_model[col].apply(
        lambda x: -9.300 + 0.274 * x if not pd.isna(x) else np.nan  # Calculate d18Ow
    )

# Display the combined data with d18Ow and d18Ow_SE columns
d18Ow_HadCM_old_4PIC_columns = [col for col in Lutetian_HadCM_old_4PIC_model.columns if col.endswith('_d18Ow')]
print("d18Ow values for all model outcomes:\n", Lutetian_HadCM_old_4PIC_model[d18Ow_HadCM_old_4PIC_columns].head())
d18Ow values for all model outcomes:
    ja_SSS_d18Ow  fb_SSS_d18Ow  mr_SSS_d18Ow  ar_SSS_d18Ow  my_SSS_d18Ow  \
0      2.730385      2.744889      2.747529      2.741694      2.738172   
1      2.795991      2.802639      2.805744      2.804372      2.808415   
2      2.837809      2.840615      2.840784      2.840007      2.851089   
3      2.777538      2.785695      2.791531      2.788105      2.786381   
4      2.809492      2.814421      2.818105      2.819479      2.818072   

   jn_SSS_d18Ow  jl_SSS_d18Ow  ag_SSS_d18Ow  sp_SSS_d18Ow  ot_SSS_d18Ow  \
0      2.750210      2.759200      2.772942      2.769145      2.745299   
1      2.828405      2.840431      2.852451      2.850035      2.827458   
2      2.875549      2.889367      2.895949      2.892115      2.864288   
3      2.799461      2.820661      2.842595      2.836395      2.806944   
4      2.827237      2.844929      2.866786      2.863590      2.838464   

   nv_SSS_d18Ow  dc_SSS_d18Ow  
0      2.729710      2.726179  
1      2.811291      2.800433  
2      2.849760      2.841525  
3      2.785955      2.777641  
4      2.820463      2.812720  

Calculate carbonate oxygen isotope value from SST and seawater oxygen isotope data using Grossman and Ku (1986) with the VPDB-VSMOW scale correction by Gonfiantini et al. (1995) and Dettman et al. (1999)¶

In [35]:
# Start with calculating d18Oc values for CESM model with 4x pre-industrial CO2
# Iterate over each model and calculate d18Oc values
for index, row in Lutetian_CESM_4PIC_model.iterrows():
    # Iterate over each month
    for month in months:
        SST = row[f"{month}_SST"]
        d18Ow = row[f"{month}_SSS_d18Ow"]
        if not pd.isna(SST) and not pd.isna(d18Ow):
            d18Oc = (20.6 - SST) / 4.34 + (d18Ow - 0.27)
        else:
            d18Oc = np.nan
        # Add the calculated d18Oc value to the DataFrame
        Lutetian_CESM_4PIC_model.loc[index, f"{month}_d18Oc"] = d18Oc

# Display the updated DataFrame
print(Lutetian_CESM_4PIC_model.head())

# Now calculating d18Oc values for CESM model with 2x pre-industrial CO2
# Iterate over each model and calculate d18Oc values
for index, row in Lutetian_CESM_2PIC_model.iterrows():
    # Iterate over each month
    for month in months:
        SST = row[f"{month}_SST"]
        d18Ow = row[f"{month}_SSS_d18Ow"]
        if not pd.isna(SST) and not pd.isna(d18Ow):
            d18Oc = (20.6 - SST) / 4.34 + (d18Ow - 0.27)
        else:
            d18Oc = np.nan
        # Add the calculated d18Oc value to the DataFrame
        Lutetian_CESM_2PIC_model.loc[index, f"{month}_d18Oc"] = d18Oc

# Display the updated DataFrame
print(Lutetian_CESM_2PIC_model.head())

# Now calculating d18Oc values for new HadCM model with 1x pre-industrial CO2
# Iterate over each model and calculate d18Oc values
for index, row in Lutetian_HadCM_new_1PIC_model.iterrows():
    # Iterate over each month
    for month in months:
        SST = row[f"{month}_SST"]
        d18Ow = row[f"{month}_SSS_d18Ow"]
        if not pd.isna(SST) and not pd.isna(d18Ow):
            d18Oc = (20.6 - SST) / 4.34 + (d18Ow - 0.27)
        else:
            d18Oc = np.nan
        # Add the calculated d18Oc value to the DataFrame
        Lutetian_HadCM_new_1PIC_model.loc[index, f"{month}_d18Oc"] = d18Oc

# Display the updated DataFrame
print(Lutetian_HadCM_new_1PIC_model.head())

# Now calculating d18Oc values for new HadCM model with 2x pre-industrial CO2
# Iterate over each model and calculate d18Oc values
for index, row in Lutetian_HadCM_new_2PIC_model.iterrows():
    # Iterate over each month
    for month in months:
        SST = row[f"{month}_SST"]
        d18Ow = row[f"{month}_SSS_d18Ow"]
        if not pd.isna(SST) and not pd.isna(d18Ow):
            d18Oc = (20.6 - SST) / 4.34 + (d18Ow - 0.27)
        else:
            d18Oc = np.nan
        # Add the calculated d18Oc value to the DataFrame
        Lutetian_HadCM_new_2PIC_model.loc[index, f"{month}_d18Oc"] = d18Oc

# Display the updated DataFrame
print(Lutetian_HadCM_new_2PIC_model.head())

# Now calculating d18Oc values for new HadCM model with 1056 ppm CO2
# Iterate over each model and calculate d18Oc values
for index, row in Lutetian_HadCM_new_1056ppm_model.iterrows():
    # Iterate over each month
    for month in months:
        SST = row[f"{month}_SST"]
        d18Ow = row[f"{month}_SSS_d18Ow"]
        if not pd.isna(SST) and not pd.isna(d18Ow):
            d18Oc = (20.6 - SST) / 4.34 + (d18Ow - 0.27)
        else:
            d18Oc = np.nan
        # Add the calculated d18Oc value to the DataFrame
        Lutetian_HadCM_new_1056ppm_model.loc[index, f"{month}_d18Oc"] = d18Oc

# Display the updated DataFrame
print(Lutetian_HadCM_new_1056ppm_model.head())

# Now calculating d18Oc values for old HadCM model with 2x pre-industrial CO2
# Iterate over each model and calculate d18Oc values
for index, row in Lutetian_HadCM_old_2PIC_model.iterrows():
    # Iterate over each month
    for month in months:
        SST = row[f"{month}_SST"]
        d18Ow = row[f"{month}_SSS_d18Ow"]
        if not pd.isna(SST) and not pd.isna(d18Ow):
            d18Oc = (20.6 - SST) / 4.34 + (d18Ow - 0.27)
        else:
            d18Oc = np.nan
        # Add the calculated d18Oc value to the DataFrame
        Lutetian_HadCM_old_2PIC_model.loc[index, f"{month}_d18Oc"] = d18Oc

# Display the updated DataFrame
print(Lutetian_HadCM_old_2PIC_model.head())

# Now calculating d18Oc values for old HadCM model with 4x pre-industrial CO2
# Iterate over each model and calculate d18Oc values
for index, row in Lutetian_HadCM_old_4PIC_model.iterrows():
    # Iterate over each month
    for month in months:
        SST = row[f"{month}_SST"]
        d18Ow = row[f"{month}_SSS_d18Ow"]
        if not pd.isna(SST) and not pd.isna(d18Ow):
            d18Oc = (20.6 - SST) / 4.34 + (d18Ow - 0.27)
        else:
            d18Oc = np.nan
        # Add the calculated d18Oc value to the DataFrame
        Lutetian_HadCM_old_4PIC_model.loc[index, f"{month}_d18Oc"] = d18Oc

# Display the updated DataFrame
print(Lutetian_HadCM_old_4PIC_model.head())
   Cell     ja_SAT     fb_SAT     mr_SAT     ar_SAT     my_SAT     jn_SAT  \
0     1  11.282648  12.089380  13.829187  16.709039  22.411493  27.940820   
1     2  21.823206  22.185327  23.480707  25.735864  30.242242  35.107660   
2     3  21.909296  22.198022  23.222040  25.234583  29.434015  34.056543   
3     4  22.503198  22.530481  23.346246  25.152704  28.970605  33.480951   
4     5  21.393762  21.576868  22.996118  25.669275  30.826440  36.038263   

      jl_SAT     ag_SAT     sp_SAT  ...  mr_d18Oc  ar_d18Oc  my_d18Oc  \
0  30.968195  31.072290  26.694391  ... -0.873077 -1.040673 -1.619817   
1  38.680688  39.036523  35.629755  ... -0.799470 -0.929937 -1.466061   
2  38.089227  38.691492  35.554956  ... -0.754007 -0.877557 -1.403951   
3  37.780298  38.492792  35.470605  ... -1.136514 -1.384207 -2.130491   
4  40.872888  40.882013  36.701257  ... -1.122320 -1.360099 -2.106644   

   jn_d18Oc  jl_d18Oc  ag_d18Oc  sp_d18Oc  ot_d18Oc  nv_d18Oc  dc_d18Oc  
0 -2.513306 -3.213928 -3.583698 -3.367792 -2.744058 -2.032903 -1.408096  
1 -2.347593 -3.014437 -3.384486 -3.208780 -2.633968 -1.938649 -1.313754  
2 -2.289134 -2.948919 -3.317429 -3.148663 -2.580306 -1.883936 -1.240408  
3 -3.116770 -3.959694 -4.334650 -4.195826 -3.656621 -2.769984 -1.943248  
4 -3.107112 -3.975039 -4.357027 -4.219610 -3.656945 -2.755215 -1.950705  

[5 rows x 121 columns]
   Cell     ja_SAT     fb_SAT     mr_SAT     ar_SAT     my_SAT     jn_SAT  \
0     1   8.079706   8.682245  10.292291  13.623804  18.543329  22.827844   
1     2  18.723108  19.036798  20.318903  22.775720  26.905450  31.019128   
2     3  18.902612  19.163934  20.205408  22.355096  26.210016  30.252496   
3     4  19.552850  19.557764  20.425623  22.352350  25.905756  29.882379   
4     5  18.329370  18.452631  19.794916  22.507562  27.185938  31.563654   

      jl_SAT     ag_SAT     sp_SAT  ...  mr_d18Oc  ar_d18Oc  my_d18Oc  \
0  25.661005  25.911890  22.544611  ... -0.251207 -0.457940 -1.035783   
1  34.275934  34.816797  31.946375  ... -0.186319 -0.348003 -0.886515   
2  34.047083  34.686151  32.002588  ... -0.141044 -0.294629 -0.829306   
3  33.956262  34.617273  31.891870  ... -0.279467 -0.573045 -1.337027   
4  36.184412  36.466760  32.711786  ... -0.264183 -0.545776 -1.311192   

   jn_d18Oc  jl_d18Oc  ag_d18Oc  sp_d18Oc  ot_d18Oc  nv_d18Oc  dc_d18Oc  
0 -1.881269 -2.576888 -2.909747 -2.685377 -2.032326 -1.304283 -0.662541  
1 -1.713226 -2.383224 -2.730425 -2.549758 -1.941088 -1.222027 -0.576549  
2 -1.654628 -2.321103 -2.669299 -2.494446 -1.898522 -1.172672 -0.504181  
3 -2.293682 -3.076797 -3.480791 -3.346192 -2.751792 -1.868905 -1.014725  
4 -2.280590 -3.088334 -3.501189 -3.361654 -2.745354 -1.846001 -1.017308  

[5 rows x 121 columns]
   Cell     ja_SAT     fb_SAT     mr_SAT     ar_SAT     my_SAT     jn_SAT  \
0     1   8.052789   7.992517   8.733209  10.359064  13.972986  19.524438   
1     2   5.543665   5.446466   6.303369   8.327386  12.788965  18.906274   
2     3   5.441797   5.020135   5.603723   7.323083  11.379724  17.331293   
3     4  11.657343  11.682520  12.354303  13.548639  16.459161  21.680658   
4     5   3.336206   5.344659   8.210504  11.033441  15.833429  20.868097   

      jl_SAT     ag_SAT     sp_SAT  ...  mr_d18Oc  ar_d18Oc  my_d18Oc  \
0  24.154474  25.112024  22.214838  ...  1.371498  1.247086  0.758522   
1  23.355554  24.378473  21.271326  ...  1.335512  1.239549  0.778126   
2  22.398523  23.914362  21.047418  ...  1.927412  1.703638  1.036772   
3  25.439905  26.119257  24.086908  ...  1.362663  1.313629  0.937249   
4  23.159937  23.440515  20.537500  ...  1.588500  1.521920  1.041418   

   jn_d18Oc  jl_d18Oc  ag_d18Oc  sp_d18Oc  ot_d18Oc  nv_d18Oc  dc_d18Oc  
0 -0.204534 -0.812510 -0.975899 -0.837487 -0.201872  0.513953  0.996075  
1 -0.170957 -0.769120 -0.937684 -0.817608 -0.226889  0.443263  0.944667  
2 -0.037282 -0.707649 -0.900912 -0.713900 -0.038772  0.678716  1.281174  
3 -0.104788 -0.920888 -1.116881 -0.834474 -0.204629  0.436719  0.866669  
4 -0.078969 -0.849627 -1.022401 -0.739666 -0.096670  0.608511  1.076184  

[5 rows x 121 columns]
   Cell     ja_SAT     fb_SAT     mr_SAT     ar_SAT     my_SAT     jn_SAT  \
0     1  12.032495  11.765405  12.540948  14.017786  17.638818  22.951166   
1     2  10.032343   9.614069  10.567499  12.368372  16.857782  23.125818   
2     3  10.042474   9.279749   9.883508  11.388208  15.628229  21.994348   
3     4  15.231805  14.956903  15.680139  16.795190  19.790338  24.812463   
4     5   7.854364   8.944025  11.926355  14.481989  19.159235  24.058344   

      jl_SAT     ag_SAT     sp_SAT  ...  mr_d18Oc  ar_d18Oc  my_d18Oc  \
0  27.410181  28.291254  25.576105  ...  0.868118  0.733481  0.253210   
1  27.034113  27.580316  24.560754  ...  0.821608  0.719385  0.261080   
2  26.338739  27.108881  24.157251  ...  1.337524  1.117325  0.431039   
3  28.288263  28.865594  26.970605  ...  0.858103  0.800370  0.399973   
4  26.157434  26.275842  23.426965  ...  1.056110  0.963794  0.449333   

   jn_d18Oc  jl_d18Oc  ag_d18Oc  sp_d18Oc  ot_d18Oc  nv_d18Oc  dc_d18Oc  
0 -0.624277 -1.172320 -1.371561 -1.284367 -0.671433  0.044402  0.524114  
1 -0.632101 -1.163279 -1.343080 -1.269951 -0.683597 -0.018013  0.460165  
2 -0.589934 -1.150781 -1.326708 -1.184240 -0.524181  0.173744  0.744560  
3 -0.562882 -1.351832 -1.570835 -1.337008 -0.711914 -0.066910  0.371023  
4 -0.620587 -1.316765 -1.477848 -1.240102 -0.594261  0.094205  0.551104  

[5 rows x 121 columns]
   Cell     ja_SAT     fb_SAT     mr_SAT     ar_SAT     my_SAT     jn_SAT  \
0     1  14.752985  14.494897  14.980402  16.575220  20.000818  25.204980   
1     2  12.996912  12.753046  13.208704  15.260828  19.392999  25.608850   
2     3  13.127679  12.599512  12.679742  14.343317  18.218500  24.699243   
3     4  17.809625  17.621484  17.975031  19.288171  22.094263  26.878717   
4     5  11.005304  12.533258  14.417230  17.510217  21.609277  26.559656   

      jl_SAT     ag_SAT     sp_SAT  ...  mr_d18Oc  ar_d18Oc  my_d18Oc  \
0  29.662347  30.615137  28.027460  ...  0.462286  0.319492 -0.117976   
1  29.630823  30.056573  27.234857  ...  0.420872  0.318065 -0.094086   
2  28.905939  29.489587  26.775018  ...  0.896351  0.671169  0.053261   
3  30.409326  31.094934  29.279382  ...  0.450243  0.387609 -0.001984   
4  29.221490  29.027551  26.355951  ...  0.630011  0.541336  0.059345   

   jn_d18Oc  jl_d18Oc  ag_d18Oc  sp_d18Oc  ot_d18Oc  nv_d18Oc  dc_d18Oc  
0 -0.893339 -1.401199 -1.663044 -1.615631 -1.046066 -0.307489  0.145241  
1 -0.916587 -1.447047 -1.683003 -1.627250 -1.087843 -0.367076  0.087612  
2 -0.909284 -1.470256 -1.696925 -1.566963 -0.965545 -0.187116  0.359146  
3 -0.865929 -1.592123 -1.891272 -1.687934 -1.105678 -0.449740 -0.027298  
4 -0.917299 -1.601847 -1.839061 -1.629993 -1.019839 -0.290049  0.147674  

[5 rows x 121 columns]
   Cell     ja_SAT     fb_SAT     mr_SAT     ar_SAT     my_SAT     jn_SAT  \
0     1  16.109460  16.027917  16.557794  17.969568  20.876367  24.644067   
1     2  14.491327  14.465814  15.096796  16.632349  20.268671  25.111902   
2     3  14.220056  13.856958  14.220026  15.771631  19.406030  24.685876   
3     4  18.878229  18.639429  18.971124  20.211633  22.895258  26.576044   
4     5  10.043237  12.065576  15.218744  18.920587  23.262933  28.577478   

      jl_SAT     ag_SAT     sp_SAT  ...  mr_d18Oc  ar_d18Oc  my_d18Oc  \
0  28.467523  30.818384  29.538446  ...  2.291533  2.078768  1.546487   
1  29.014185  31.189355  29.456750  ...  2.390405  2.190546  1.623027   
2  28.935297  30.628656  28.646417  ...  2.603273  2.345437  1.680343   
3  29.851801  31.372522  30.517450  ...  2.481481  2.289573  1.718124   
4  31.001825  31.300806  27.688562  ...  2.655554  2.478183  1.930503   

   jn_d18Oc  jl_d18Oc  ag_d18Oc  sp_d18Oc  ot_d18Oc  nv_d18Oc  dc_d18Oc  
0  0.806258  0.375497  0.130180  0.084777  0.546801  1.247116  1.817300  
1  0.810241  0.360604  0.118713  0.102642  0.590819  1.283430  1.878680  
2  0.817935  0.410225  0.190672  0.165803  0.717999  1.441631  2.071117  
3  0.868131  0.315540  0.057481  0.142721  0.749011  1.494767  2.041653  
4  1.077646  0.468864  0.198060  0.267340  0.940486  1.678493  2.245521  

[5 rows x 121 columns]
   Cell     ja_SAT     fb_SAT     mr_SAT     ar_SAT     my_SAT     jn_SAT  \
0     1  16.109460  16.027917  16.557794  17.969568  20.876367  24.644067   
1     2  14.491327  14.465814  15.096796  16.632349  20.268671  25.111902   
2     3  14.220056  13.856958  14.220026  15.771631  19.406030  24.685876   
3     4  18.878229  18.639429  18.971124  20.211633  22.895258  26.576044   
4     5  10.043237  12.065576  15.218744  18.920587  23.262933  28.577478   

      jl_SAT     ag_SAT     sp_SAT  ...  mr_d18Oc  ar_d18Oc  my_d18Oc  \
0  28.467523  30.818384  29.538446  ...  2.291533  2.078768  1.546487   
1  29.014185  31.189355  29.456750  ...  2.390405  2.190546  1.623027   
2  28.935297  30.628656  28.646417  ...  2.603273  2.345437  1.680343   
3  29.851801  31.372522  30.517450  ...  2.481481  2.289573  1.718124   
4  31.001825  31.300806  27.688562  ...  2.655554  2.478183  1.930503   

   jn_d18Oc  jl_d18Oc  ag_d18Oc  sp_d18Oc  ot_d18Oc  nv_d18Oc  dc_d18Oc  
0  0.806258  0.375497  0.130180  0.084777  0.546801  1.247116  1.817300  
1  0.810241  0.360604  0.118713  0.102642  0.590819  1.283430  1.878680  
2  0.817935  0.410225  0.190672  0.165803  0.717999  1.441631  2.071117  
3  0.868131  0.315540  0.057481  0.142721  0.749011  1.494767  2.041653  
4  1.077646  0.468864  0.198060  0.267340  0.940486  1.678493  2.245521  

[5 rows x 121 columns]

Calculate the monthly prior for model SST- and SAT-derived D47 values and SSS-derived seawater oxygen isotope values with propagated uncertainty¶

In [36]:
HadCM_old_4PIC_model_variances_SST = Lutetian_HadCM_old_4PIC_model[[f"{month}_SST_D47" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
HadCM_old_4PIC_model_variances_SAT = Lutetian_HadCM_old_4PIC_model[[f"{month}_SAT_D47" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
HadCM_old_4PIC_model_variances_d18Ow = Lutetian_HadCM_old_4PIC_model[[f"{month}_SSS_d18Ow" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
HadCM_old_4PIC_model_variances_d18Oc = Lutetian_HadCM_old_4PIC_model[[f"{month}_d18Oc" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
HadCM_old_4PIC_calibration_variances_SST = (Lutetian_HadCM_old_4PIC_model[[f"{month}_SST_D47_SE" for month in months]] ** 2).mean(axis = 0, skipna = True)  # Compute variance on measurements
HadCM_old_4PIC_calibration_variances_SAT = (Lutetian_HadCM_old_4PIC_model[[f"{month}_SAT_D47_SE" for month in months]] ** 2).mean(axis = 0, skipna = True)  # Compute variance on measurements
In [37]:
# Set the weights of the data based on the standard errors
weights_monthly_CESM_4PIC_SST_D47 = 1 / Lutetian_CESM_4PIC_model[[f"{month}_SST_D47_SE" for month in months]] ** 2
weights_monthly_CESM_4PIC_SAT_D47 = 1 / Lutetian_CESM_4PIC_model[[f"{month}_SAT_D47_SE" for month in months]] ** 2
weights_monthly_CESM_2PIC_SST_D47 = 1 / Lutetian_CESM_2PIC_model[[f"{month}_SST_D47_SE" for month in months]] ** 2
weights_monthly_CESM_2PIC_SAT_D47 = 1 / Lutetian_CESM_2PIC_model[[f"{month}_SAT_D47_SE" for month in months]] ** 2
weights_monthly_HadCM_new_1PIC_SST_D47 = 1 / Lutetian_HadCM_new_1PIC_model[[f"{month}_SST_D47_SE" for month in months]] ** 2
weights_monthly_HadCM_new_1PIC_SAT_D47 = 1 / Lutetian_HadCM_new_1PIC_model[[f"{month}_SAT_D47_SE" for month in months]] ** 2
weights_monthly_HadCM_new_2PIC_SST_D47 = 1 / Lutetian_HadCM_new_2PIC_model[[f"{month}_SST_D47_SE" for month in months]] ** 2
weights_monthly_HadCM_new_2PIC_SAT_D47 = 1 / Lutetian_HadCM_new_2PIC_model[[f"{month}_SAT_D47_SE" for month in months]] ** 2
weights_monthly_HadCM_new_1056ppm_SST_D47 = 1 / Lutetian_HadCM_new_1056ppm_model[[f"{month}_SST_D47_SE" for month in months]] ** 2
weights_monthly_HadCM_new_1056ppm_SAT_D47 = 1 / Lutetian_HadCM_new_1056ppm_model[[f"{month}_SAT_D47_SE" for month in months]] ** 2
weights_monthly_HadCM_old_2PIC_SST_D47 = 1 / Lutetian_HadCM_old_2PIC_model[[f"{month}_SST_D47_SE" for month in months]] ** 2
weights_monthly_HadCM_old_2PIC_SAT_D47 = 1 / Lutetian_HadCM_old_2PIC_model[[f"{month}_SAT_D47_SE" for month in months]] ** 2
weights_monthly_HadCM_old_4PIC_SST_D47 = 1 / Lutetian_HadCM_old_4PIC_model[[f"{month}_SST_D47_SE" for month in months]] ** 2
weights_monthly_HadCM_old_4PIC_SAT_D47 = 1 / Lutetian_HadCM_old_4PIC_model[[f"{month}_SAT_D47_SE" for month in months]] ** 2

# Change the column suffixes from "_D47_SE" to "_D47" in weights_monthly_CESM_4PIC_SST_D47 to match the headers of the D47 matrix later for multiplication
weights_monthly_CESM_4PIC_SST_D47.columns = [col.replace('_SST_D47_SE', '_SST_D47') for col in weights_monthly_CESM_4PIC_SST_D47.columns]
weights_monthly_CESM_4PIC_SAT_D47.columns = [col.replace('_SAT_D47_SE', '_SAT_D47') for col in weights_monthly_CESM_4PIC_SAT_D47.columns]
weights_monthly_CESM_2PIC_SST_D47.columns = [col.replace('_SST_D47_SE', '_SST_D47') for col in weights_monthly_CESM_2PIC_SST_D47.columns]
weights_monthly_CESM_2PIC_SAT_D47.columns = [col.replace('_SAT_D47_SE', '_SAT_D47') for col in weights_monthly_CESM_2PIC_SAT_D47.columns]
weights_monthly_HadCM_new_1PIC_SST_D47.columns = [col.replace('_SST_D47_SE', '_SST_D47') for col in weights_monthly_HadCM_new_1PIC_SST_D47.columns]
weights_monthly_HadCM_new_1PIC_SAT_D47.columns = [col.replace('_SAT_D47_SE', '_SAT_D47') for col in weights_monthly_HadCM_new_1PIC_SAT_D47.columns]
weights_monthly_HadCM_new_2PIC_SST_D47.columns = [col.replace('_SST_D47_SE', '_SST_D47') for col in weights_monthly_HadCM_new_2PIC_SST_D47.columns]
weights_monthly_HadCM_new_2PIC_SAT_D47.columns = [col.replace('_SAT_D47_SE', '_SAT_D47') for col in weights_monthly_HadCM_new_2PIC_SAT_D47.columns]
weights_monthly_HadCM_new_1056ppm_SST_D47.columns = [col.replace('_SST_D47_SE', '_SST_D47') for col in weights_monthly_HadCM_new_1056ppm_SST_D47.columns]
weights_monthly_HadCM_new_1056ppm_SAT_D47.columns = [col.replace('_SAT_D47_SE', '_SAT_D47') for col in weights_monthly_HadCM_new_1056ppm_SAT_D47.columns]
weights_monthly_HadCM_old_2PIC_SST_D47.columns = [col.replace('_SST_D47_SE', '_SST_D47') for col in weights_monthly_HadCM_old_2PIC_SST_D47.columns]
weights_monthly_HadCM_old_2PIC_SAT_D47.columns = [col.replace('_SAT_D47_SE', '_SAT_D47') for col in weights_monthly_HadCM_old_2PIC_SAT_D47.columns]
weights_monthly_HadCM_old_4PIC_SST_D47.columns = [col.replace('_SST_D47_SE', '_SST_D47') for col in weights_monthly_HadCM_old_4PIC_SST_D47.columns]
weights_monthly_HadCM_old_4PIC_SAT_D47.columns = [col.replace('_SAT_D47_SE', '_SAT_D47') for col in weights_monthly_HadCM_old_4PIC_SAT_D47.columns]

# Prior D47 estimates from CESM model with 4x preindustrial pCO2 (weighted mean)
mu_prior_CESM_4PIC_SST_D47_monthly = np.array((Lutetian_CESM_4PIC_model[[f"{month}_SST_D47" for month in months]] * weights_monthly_CESM_4PIC_SST_D47).sum(axis = 0, skipna = True) / weights_monthly_CESM_4PIC_SST_D47.sum(axis = 0, skipna = True)) # Calculate weighted monthly mean D47 values and convert to numpy array
mu_prior_CESM_4PIC_SAT_D47_monthly = np.array((Lutetian_CESM_4PIC_model[[f"{month}_SAT_D47" for month in months]] * weights_monthly_CESM_4PIC_SAT_D47).sum(axis = 0, skipna = True) / weights_monthly_CESM_4PIC_SAT_D47.sum(axis = 0, skipna = True)) # Calculate weighted monthly mean D47 values and convert to numpy array
mu_prior_CESM_2PIC_SST_D47_monthly = np.array((Lutetian_CESM_2PIC_model[[f"{month}_SST_D47" for month in months]] * weights_monthly_CESM_2PIC_SST_D47).sum(axis = 0, skipna = True) / weights_monthly_CESM_2PIC_SST_D47.sum(axis = 0, skipna = True)) # Calculate weighted monthly mean D47 values and convert to numpy array
mu_prior_CESM_2PIC_SAT_D47_monthly = np.array((Lutetian_CESM_2PIC_model[[f"{month}_SAT_D47" for month in months]] * weights_monthly_CESM_2PIC_SAT_D47).sum(axis = 0, skipna = True) / weights_monthly_CESM_2PIC_SAT_D47.sum(axis = 0, skipna = True)) # Calculate weighted monthly mean D47 values and convert to numpy array
mu_prior_HadCM_new_1PIC_SST_D47_monthly = np.array((Lutetian_HadCM_new_1PIC_model[[f"{month}_SST_D47" for month in months]] * weights_monthly_HadCM_new_1PIC_SST_D47).sum(axis = 0, skipna = True) / weights_monthly_HadCM_new_1PIC_SST_D47.sum(axis = 0, skipna = True)) # Calculate weighted monthly mean D47 values and convert to numpy array
mu_prior_HadCM_new_1PIC_SAT_D47_monthly = np.array((Lutetian_HadCM_new_1PIC_model[[f"{month}_SAT_D47" for month in months]] * weights_monthly_HadCM_new_1PIC_SAT_D47).sum(axis = 0, skipna = True) / weights_monthly_HadCM_new_1PIC_SAT_D47.sum(axis = 0, skipna = True)) # Calculate weighted monthly mean D47 values and convert to numpy array
mu_prior_HadCM_new_2PIC_SST_D47_monthly = np.array((Lutetian_HadCM_new_2PIC_model[[f"{month}_SST_D47" for month in months]] * weights_monthly_HadCM_new_2PIC_SST_D47).sum(axis = 0, skipna = True) / weights_monthly_HadCM_new_2PIC_SST_D47.sum(axis = 0, skipna = True)) # Calculate weighted monthly mean D47 values and convert to numpy array
mu_prior_HadCM_new_2PIC_SAT_D47_monthly = np.array((Lutetian_HadCM_new_2PIC_model[[f"{month}_SAT_D47" for month in months]] * weights_monthly_HadCM_new_2PIC_SAT_D47).sum(axis = 0, skipna = True) / weights_monthly_HadCM_new_2PIC_SAT_D47.sum(axis = 0, skipna = True)) # Calculate weighted monthly mean D47 values and convert to numpy array
mu_prior_HadCM_new_1056ppm_SST_D47_monthly = np.array((Lutetian_HadCM_new_1056ppm_model[[f"{month}_SST_D47" for month in months]] * weights_monthly_HadCM_new_1056ppm_SST_D47).sum(axis = 0, skipna = True) / weights_monthly_HadCM_new_1056ppm_SST_D47.sum(axis = 0, skipna = True)) # Calculate weighted monthly mean D47 values and convert to numpy array
mu_prior_HadCM_new_1056ppm_SAT_D47_monthly = np.array((Lutetian_HadCM_new_1056ppm_model[[f"{month}_SAT_D47" for month in months]] * weights_monthly_HadCM_new_1056ppm_SAT_D47).sum(axis = 0, skipna = True) / weights_monthly_HadCM_new_1056ppm_SAT_D47.sum(axis = 0, skipna = True)) # Calculate weighted monthly mean D47 values and convert to numpy array
mu_prior_HadCM_old_2PIC_SST_D47_monthly = np.array((Lutetian_HadCM_old_2PIC_model[[f"{month}_SST_D47" for month in months]] * weights_monthly_HadCM_old_2PIC_SST_D47).sum(axis = 0, skipna = True) / weights_monthly_HadCM_old_2PIC_SST_D47.sum(axis = 0, skipna = True)) # Calculate weighted monthly mean D47 values and convert to numpy array
mu_prior_HadCM_old_2PIC_SAT_D47_monthly = np.array((Lutetian_HadCM_old_2PIC_model[[f"{month}_SAT_D47" for month in months]] * weights_monthly_HadCM_old_2PIC_SAT_D47).sum(axis = 0, skipna = True) / weights_monthly_HadCM_old_2PIC_SAT_D47.sum(axis = 0, skipna = True)) # Calculate weighted monthly mean D47 values and convert to numpy array
mu_prior_HadCM_old_4PIC_SST_D47_monthly = np.array((Lutetian_HadCM_old_4PIC_model[[f"{month}_SST_D47" for month in months]] * weights_monthly_HadCM_old_4PIC_SST_D47).sum(axis = 0, skipna = True) / weights_monthly_HadCM_old_4PIC_SST_D47.sum(axis = 0, skipna = True)) # Calculate weighted monthly mean D47 values and convert to numpy array
mu_prior_HadCM_old_4PIC_SAT_D47_monthly = np.array((Lutetian_HadCM_old_4PIC_model[[f"{month}_SAT_D47" for month in months]] * weights_monthly_HadCM_old_4PIC_SAT_D47).sum(axis = 0, skipna = True) / weights_monthly_HadCM_old_4PIC_SAT_D47.sum(axis = 0, skipna = True)) # Calculate weighted monthly mean D47 values and convert to numpy array

# Calculate simple (unweighted) mean for monthly d18Ow values
mu_prior_CESM_4PIC_SSS_d18Ow_monthly = np.array(Lutetian_CESM_4PIC_model[[f"{month}_SSS_d18Ow" for month in months]].mean(axis=0, skipna=True))
mu_prior_CESM_2PIC_SSS_d18Ow_monthly = np.array(Lutetian_CESM_2PIC_model[[f"{month}_SSS_d18Ow" for month in months]].mean(axis=0, skipna=True))
mu_prior_HadCM_new_1PIC_SSS_d18Ow_monthly = np.array(Lutetian_HadCM_new_1PIC_model[[f"{month}_SSS_d18Ow" for month in months]].mean(axis=0, skipna=True))
mu_prior_HadCM_new_2PIC_SSS_d18Ow_monthly = np.array(Lutetian_HadCM_new_2PIC_model[[f"{month}_SSS_d18Ow" for month in months]].mean(axis=0, skipna=True))
mu_prior_HadCM_new_1056ppm_SSS_d18Ow_monthly = np.array(Lutetian_HadCM_new_1056ppm_model[[f"{month}_SSS_d18Ow" for month in months]].mean(axis=0, skipna=True))
mu_prior_HadCM_old_2PIC_SSS_d18Ow_monthly = np.array(Lutetian_HadCM_old_2PIC_model[[f"{month}_SSS_d18Ow" for month in months]].mean(axis=0, skipna=True))
mu_prior_HadCM_old_4PIC_SSS_d18Ow_monthly = np.array(Lutetian_HadCM_old_4PIC_model[[f"{month}_SSS_d18Ow" for month in months]].mean(axis=0, skipna=True))
mu_prior_CESM_4PIC_d18Oc_monthly = np.array(Lutetian_CESM_4PIC_model[[f"{month}_d18Oc" for month in months]].mean(axis=0, skipna=True))
mu_prior_CESM_2PIC_d18Oc_monthly = np.array(Lutetian_CESM_2PIC_model[[f"{month}_d18Oc" for month in months]].mean(axis=0, skipna=True))
mu_prior_HadCM_new_1PIC_d18Oc_monthly = np.array(Lutetian_HadCM_new_1PIC_model[[f"{month}_d18Oc" for month in months]].mean(axis=0, skipna=True))
mu_prior_HadCM_new_2PIC_d18Oc_monthly = np.array(Lutetian_HadCM_new_2PIC_model[[f"{month}_d18Oc" for month in months]].mean(axis=0, skipna=True))
mu_prior_HadCM_new_1056ppm_d18Oc_monthly = np.array(Lutetian_HadCM_new_1056ppm_model[[f"{month}_d18Oc" for month in months]].mean(axis=0, skipna=True))
mu_prior_HadCM_old_2PIC_d18Oc_monthly = np.array(Lutetian_HadCM_old_2PIC_model[[f"{month}_d18Oc" for month in months]].mean(axis=0, skipna=True))
mu_prior_HadCM_old_4PIC_d18Oc_monthly = np.array(Lutetian_HadCM_old_4PIC_model[[f"{month}_d18Oc" for month in months]].mean(axis=0, skipna=True))

# Decompose variance within and between model outcomes
CESM_4PIC_model_variances_SST = Lutetian_CESM_4PIC_model[[f"{month}_SST_D47" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
CESM_4PIC_model_variances_SAT = Lutetian_CESM_4PIC_model[[f"{month}_SAT_D47" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
CESM_4PIC_model_variances_d18Ow = Lutetian_CESM_4PIC_model[[f"{month}_SSS_d18Ow" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
CESM_4PIC_model_variances_d18Oc = Lutetian_CESM_4PIC_model[[f"{month}_d18Oc" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
CESM_4PIC_calibration_variances_SST = (Lutetian_CESM_4PIC_model[[f"{month}_SST_D47_SE" for month in months]] ** 2).mean(axis = 0, skipna = True)  # Compute variance on measurements
CESM_4PIC_calibration_variances_SAT = (Lutetian_CESM_4PIC_model[[f"{month}_SAT_D47_SE" for month in months]] ** 2).mean(axis = 0, skipna = True)  # Compute variance on measurements

CESM_2PIC_model_variances_SST = Lutetian_CESM_2PIC_model[[f"{month}_SST_D47" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
CESM_2PIC_model_variances_SAT = Lutetian_CESM_2PIC_model[[f"{month}_SAT_D47" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
CESM_2PIC_model_variances_d18Ow = Lutetian_CESM_2PIC_model[[f"{month}_SSS_d18Ow" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
CESM_2PIC_model_variances_d18Oc = Lutetian_CESM_2PIC_model[[f"{month}_d18Oc" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
CESM_2PIC_calibration_variances_SST = (Lutetian_CESM_2PIC_model[[f"{month}_SST_D47_SE" for month in months]] ** 2).mean(axis = 0, skipna = True)  # Compute variance on measurements
CESM_2PIC_calibration_variances_SAT = (Lutetian_CESM_2PIC_model[[f"{month}_SAT_D47_SE" for month in months]] ** 2).mean(axis = 0, skipna = True)  # Compute variance on measurements

HadCM_new_1PIC_model_variances_SST = Lutetian_HadCM_new_1PIC_model[[f"{month}_SST_D47" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
HadCM_new_1PIC_model_variances_SAT = Lutetian_HadCM_new_1PIC_model[[f"{month}_SAT_D47" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
HadCM_new_1PIC_model_variances_d18Ow = Lutetian_HadCM_new_1PIC_model[[f"{month}_SSS_d18Ow" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
HadCM_new_1PIC_model_variances_d18Oc = Lutetian_HadCM_new_1PIC_model[[f"{month}_d18Oc" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
HadCM_new_1PIC_calibration_variances_SST = (Lutetian_HadCM_new_1PIC_model[[f"{month}_SST_D47_SE" for month in months]] ** 2).mean(axis = 0, skipna = True)  # Compute variance on measurements
HadCM_new_1PIC_calibration_variances_SAT = (Lutetian_HadCM_new_1PIC_model[[f"{month}_SAT_D47_SE" for month in months]] ** 2).mean(axis = 0, skipna = True)  # Compute variance on measurements

HadCM_new_2PIC_model_variances_SST = Lutetian_HadCM_new_2PIC_model[[f"{month}_SST_D47" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
HadCM_new_2PIC_model_variances_SAT = Lutetian_HadCM_new_2PIC_model[[f"{month}_SAT_D47" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
HadCM_new_2PIC_model_variances_d18Ow = Lutetian_HadCM_new_2PIC_model[[f"{month}_SSS_d18Ow" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
HadCM_new_2PIC_model_variances_d18Oc = Lutetian_HadCM_new_2PIC_model[[f"{month}_d18Oc" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
HadCM_new_2PIC_calibration_variances_SST = (Lutetian_HadCM_new_2PIC_model[[f"{month}_SST_D47_SE" for month in months]] ** 2).mean(axis = 0, skipna = True)  # Compute variance on measurements
HadCM_new_2PIC_calibration_variances_SAT = (Lutetian_HadCM_new_2PIC_model[[f"{month}_SAT_D47_SE" for month in months]] ** 2).mean(axis = 0, skipna = True)  # Compute variance on measurements

HadCM_new_1056ppm_model_variances_SST = Lutetian_HadCM_new_1056ppm_model[[f"{month}_SST_D47" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
HadCM_new_1056ppm_model_variances_SAT = Lutetian_HadCM_new_1056ppm_model[[f"{month}_SAT_D47" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
HadCM_new_1056ppm_model_variances_d18Ow = Lutetian_HadCM_new_1056ppm_model[[f"{month}_SSS_d18Ow" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
HadCM_new_1056ppm_model_variances_d18Oc = Lutetian_HadCM_new_1056ppm_model[[f"{month}_d18Oc" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
HadCM_new_1056ppm_calibration_variances_SST = (Lutetian_HadCM_new_1056ppm_model[[f"{month}_SST_D47_SE" for month in months]] ** 2).mean(axis = 0, skipna = True)  # Compute variance on measurements
HadCM_new_1056ppm_calibration_variances_SAT = (Lutetian_HadCM_new_1056ppm_model[[f"{month}_SAT_D47_SE" for month in months]] ** 2).mean(axis = 0, skipna = True)  # Compute variance on measurements

HadCM_old_2PIC_model_variances_SST = Lutetian_HadCM_old_2PIC_model[[f"{month}_SST_D47" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
HadCM_old_2PIC_model_variances_SAT = Lutetian_HadCM_old_2PIC_model[[f"{month}_SAT_D47" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
HadCM_old_2PIC_model_variances_d18Ow = Lutetian_HadCM_old_2PIC_model[[f"{month}_SSS_d18Ow" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
HadCM_old_2PIC_model_variances_d18Oc = Lutetian_HadCM_old_2PIC_model[[f"{month}_d18Oc" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
HadCM_old_2PIC_calibration_variances_SST = (Lutetian_HadCM_old_2PIC_model[[f"{month}_SST_D47_SE" for month in months]] ** 2).mean(axis = 0, skipna = True)  # Compute variance on measurements
HadCM_old_2PIC_calibration_variances_SAT = (Lutetian_HadCM_old_2PIC_model[[f"{month}_SAT_D47_SE" for month in months]] ** 2).mean(axis = 0, skipna = True)  # Compute variance on measurements

HadCM_old_4PIC_model_variances_SST = Lutetian_HadCM_old_4PIC_model[[f"{month}_SST_D47" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
HadCM_old_4PIC_model_variances_SAT = Lutetian_HadCM_old_4PIC_model[[f"{month}_SAT_D47" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
HadCM_old_4PIC_model_variances_d18Ow = Lutetian_HadCM_old_4PIC_model[[f"{month}_SSS_d18Ow" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
HadCM_old_4PIC_model_variances_d18Oc = Lutetian_HadCM_old_4PIC_model[[f"{month}_d18Oc" for month in months]].var(axis = 0, ddof = 1)  # Compute variance across models
HadCM_old_4PIC_calibration_variances_SST = (Lutetian_HadCM_old_4PIC_model[[f"{month}_SST_D47_SE" for month in months]] ** 2).mean(axis = 0, skipna = True)  # Compute variance on measurements
HadCM_old_4PIC_calibration_variances_SAT = (Lutetian_HadCM_old_4PIC_model[[f"{month}_SAT_D47_SE" for month in months]] ** 2).mean(axis = 0, skipna = True)  # Compute variance on measurements

# Covariance between months in prior D47 estimates from CESM model with 4x preindustrial pCO2 (weighted covariance matrix)
cov_raw_CESM_4PIC_monthly_SST = np.cov(Lutetian_CESM_4PIC_model[[f"{month}_SST_D47" for month in months]].dropna(), rowvar = False)  # Compute the covariance matrix for the raw data (without measurement uncertainty)
cov_raw_CESM_4PIC_monthly_SAT = np.cov(Lutetian_CESM_4PIC_model[[f"{month}_SAT_D47" for month in months]].dropna(), rowvar = False)  # Compute the covariance matrix for the raw data (without measurement uncertainty)
cov_raw_CESM_4PIC_monthly_d18Ow = np.cov(Lutetian_CESM_4PIC_model[[f"{month}_SSS_d18Ow" for month in months]].dropna(), rowvar = False)  # Compute the covariance matrix for the raw data (without measurement uncertainty)
cov_raw_CESM_4PIC_monthly_d18Oc = np.cov(Lutetian_CESM_4PIC_model[[f"{month}_d18Oc" for month in months]].dropna(), rowvar = False)  # Compute the covariance matrix for the raw data (without measurement uncertainty)
cov_prior_CESM_4PIC_SST_D47_monthly = cov_raw_CESM_4PIC_monthly_SST.copy() # Copy covariance matrix to add uncertainty coming from the measurements
cov_prior_CESM_4PIC_SAT_D47_monthly = cov_raw_CESM_4PIC_monthly_SAT.copy() # Copy covariance matrix to add uncertainty coming from the measurements
np.fill_diagonal(cov_prior_CESM_4PIC_SST_D47_monthly, np.diagonal(cov_raw_CESM_4PIC_monthly_SST) + CESM_4PIC_calibration_variances_SST)  # Add diagonal terms for measurement uncertainties (which have no covariance between models)
np.fill_diagonal(cov_prior_CESM_4PIC_SAT_D47_monthly, np.diagonal(cov_raw_CESM_4PIC_monthly_SAT) + CESM_4PIC_calibration_variances_SAT)  # Add diagonal terms for measurement uncertainties (which have no covariance between models)

cov_raw_CESM_2PIC_monthly_SST = np.cov(Lutetian_CESM_2PIC_model[[f"{month}_SST_D47" for month in months]].dropna(), rowvar = False)  # Compute the covariance matrix for the raw data (without measurement uncertainty)
cov_raw_CESM_2PIC_monthly_SAT = np.cov(Lutetian_CESM_2PIC_model[[f"{month}_SAT_D47" for month in months]].dropna(), rowvar = False)  # Compute the covariance matrix for the raw data (without measurement uncertainty)
cov_raw_CESM_2PIC_monthly_d18Ow = np.cov(Lutetian_CESM_2PIC_model[[f"{month}_SSS_d18Ow" for month in months]].dropna(), rowvar = False)  # Compute the covariance matrix for the raw data (without measurement uncertainty)
cov_raw_CESM_2PIC_monthly_d18Oc = np.cov(Lutetian_CESM_2PIC_model[[f"{month}_d18Oc" for month in months]].dropna(), rowvar = False)  # Compute the covariance matrix for the raw data (without measurement uncertainty)
cov_prior_CESM_2PIC_SST_D47_monthly = cov_raw_CESM_2PIC_monthly_SST.copy() # Copy covariance matrix to add uncertainty coming from the measurements
cov_prior_CESM_2PIC_SAT_D47_monthly = cov_raw_CESM_2PIC_monthly_SAT.copy() # Copy covariance matrix to add uncertainty coming from the measurements
np.fill_diagonal(cov_prior_CESM_2PIC_SST_D47_monthly, np.diagonal(cov_raw_CESM_2PIC_monthly_SST) + CESM_2PIC_calibration_variances_SST)  # Add diagonal terms for measurement uncertainties (which have no covariance between models)
np.fill_diagonal(cov_prior_CESM_2PIC_SAT_D47_monthly, np.diagonal(cov_raw_CESM_2PIC_monthly_SAT) + CESM_2PIC_calibration_variances_SAT)  # Add diagonal terms for measurement

cov_raw_HadCM_new_1PIC_monthly_SST = np.cov(Lutetian_HadCM_new_1PIC_model[[f"{month}_SST_D47" for month in months]].dropna(), rowvar = False)  # Compute the covariance matrix for the raw data (without measurement uncertainty)
cov_raw_HadCM_new_1PIC_monthly_SAT = np.cov(Lutetian_HadCM_new_1PIC_model[[f"{month}_SAT_D47" for month in months]].dropna(), rowvar = False)  # Compute the covariance matrix for the raw data (without measurement uncertainty)
cov_raw_HadCM_new_1PIC_monthly_d18Ow = np.cov(Lutetian_HadCM_new_1PIC_model[[f"{month}_SSS_d18Ow" for month in months]].dropna(), rowvar = False)  # Compute the covariance matrix for the raw data (without measurement uncertainty)
cov_raw_HadCM_new_1PIC_monthly_d18Oc = np.cov(Lutetian_HadCM_new_1PIC_model[[f"{month}_d18Oc" for month in months]].dropna(), rowvar = False)  # Compute the covariance matrix for the raw data (without measurement uncertainty)
cov_prior_HadCM_new_1PIC_SST_D47_monthly = cov_raw_HadCM_new_1PIC_monthly_SST.copy() # Copy covariance matrix to add uncertainty coming from the measurements
cov_prior_HadCM_new_1PIC_SAT_D47_monthly = cov_raw_HadCM_new_1PIC_monthly_SAT.copy() # Copy covariance matrix to add uncertainty coming from the measurements
np.fill_diagonal(cov_prior_HadCM_new_1PIC_SST_D47_monthly, np.diagonal(cov_raw_HadCM_new_1PIC_monthly_SST) + HadCM_new_1PIC_calibration_variances_SST)  # Add diagonal terms for measurement uncertainties (which have no covariance between models)
np.fill_diagonal(cov_prior_HadCM_new_1PIC_SAT_D47_monthly, np.diagonal(cov_raw_HadCM_new_1PIC_monthly_SAT) + HadCM_new_1PIC_calibration_variances_SAT)  # Add diagonal terms for measurement uncertainties (which have no covariance between models)

cov_raw_HadCM_new_2PIC_monthly_SST = np.cov(Lutetian_HadCM_new_2PIC_model[[f"{month}_SST_D47" for month in months]].dropna(), rowvar = False)  # Compute the covariance matrix for the raw data (without measurement uncertainty)
cov_raw_HadCM_new_2PIC_monthly_SAT = np.cov(Lutetian_HadCM_new_2PIC_model[[f"{month}_SAT_D47" for month in months]].dropna(), rowvar = False)  # Compute the covariance matrix for the raw data (without measurement uncertainty)
cov_raw_HadCM_new_2PIC_monthly_d18Ow = np.cov(Lutetian_HadCM_new_2PIC_model[[f"{month}_SSS_d18Ow" for month in months]].dropna(), rowvar = False)  # Compute the covariance matrix for the raw data (without measurement uncertainty)
cov_raw_HadCM_new_2PIC_monthly_d18Oc = np.cov(Lutetian_HadCM_new_2PIC_model[[f"{month}_d18Oc" for month in months]].dropna(), rowvar = False)  # Compute the covariance matrix for the raw data (without measurement uncertainty)
cov_prior_HadCM_new_2PIC_SST_D47_monthly = cov_raw_HadCM_new_2PIC_monthly_SST.copy() # Copy covariance matrix to add uncertainty coming from the measurements
cov_prior_HadCM_new_2PIC_SAT_D47_monthly = cov_raw_HadCM_new_2PIC_monthly_SAT.copy() # Copy covariance matrix to add uncertainty coming from the measurements
np.fill_diagonal(cov_prior_HadCM_new_2PIC_SST_D47_monthly, np.diagonal(cov_raw_HadCM_new_2PIC_monthly_SST) + HadCM_new_2PIC_calibration_variances_SST)  # Add diagonal terms for measurement uncertainties (which have no covariance between models)
np.fill_diagonal(cov_prior_HadCM_new_2PIC_SAT_D47_monthly, np.diagonal(cov_raw_HadCM_new_2PIC_monthly_SAT) + HadCM_new_2PIC_calibration_variances_SAT)  # Add diagonal terms for measurement uncertainties (which have no covariance between models)

cov_raw_HadCM_new_1056ppm_monthly_SST = np.cov(Lutetian_HadCM_new_1056ppm_model[[f"{month}_SST_D47" for month in months]].dropna(), rowvar = False)  # Compute the covariance matrix for the raw data (without measurement uncertainty)
cov_raw_HadCM_new_1056ppm_monthly_SAT = np.cov(Lutetian_HadCM_new_1056ppm_model[[f"{month}_SAT_D47" for month in months]].dropna(), rowvar = False)  # Compute the covariance matrix for the raw data (without measurement uncertainty)
cov_raw_HadCM_new_1056ppm_monthly_d18Ow = np.cov(Lutetian_HadCM_new_1056ppm_model[[f"{month}_SSS_d18Ow" for month in months]].dropna(), rowvar = False)  # Compute the covariance matrix for the raw data (without measurement uncertainty)
cov_raw_HadCM_new_1056ppm_monthly_d18Oc = np.cov(Lutetian_HadCM_new_1056ppm_model[[f"{month}_d18Oc" for month in months]].dropna(), rowvar = False)  # Compute the covariance matrix for the raw data (without measurement uncertainty)
cov_prior_HadCM_new_1056ppm_SST_D47_monthly = cov_raw_HadCM_new_1056ppm_monthly_SST.copy() # Copy covariance matrix to add uncertainty coming from the measurements
cov_prior_HadCM_new_1056ppm_SAT_D47_monthly = cov_raw_HadCM_new_1056ppm_monthly_SAT.copy() # Copy covariance matrix to add uncertainty coming from the measurements
np.fill_diagonal(cov_prior_HadCM_new_1056ppm_SST_D47_monthly, np.diagonal(cov_raw_HadCM_new_1056ppm_monthly_SST) + HadCM_new_1056ppm_calibration_variances_SST)  # Add diagonal terms for measurement uncertainties (which have no covariance between models)
np.fill_diagonal(cov_prior_HadCM_new_1056ppm_SAT_D47_monthly, np.diagonal(cov_raw_HadCM_new_1056ppm_monthly_SAT) + HadCM_new_1056ppm_calibration_variances_SAT)  # Add diagonal terms for measurement uncertainties (which have no covariance between models)

cov_raw_HadCM_old_2PIC_monthly_SST = np.cov(Lutetian_HadCM_old_2PIC_model[[f"{month}_SST_D47" for month in months]].dropna(), rowvar = False)  # Compute the covariance matrix for the raw data (without measurement uncertainty)
cov_raw_HadCM_old_2PIC_monthly_SAT = np.cov(Lutetian_HadCM_old_2PIC_model[[f"{month}_SAT_D47" for month in months]].dropna(), rowvar = False)  # Compute the covariance matrix for the raw data (without measurement uncertainty)
cov_raw_HadCM_old_2PIC_monthly_d18Ow = np.cov(Lutetian_HadCM_old_2PIC_model[[f"{month}_SSS_d18Ow" for month in months]].dropna(), rowvar = False)  # Compute the covariance matrix for the raw data (without measurement uncertainty)
cov_raw_HadCM_old_2PIC_monthly_d18Oc = np.cov(Lutetian_HadCM_old_2PIC_model[[f"{month}_d18Oc" for month in months]].dropna(), rowvar = False)  # Compute the covariance matrix for the raw data (without measurement uncertainty)
cov_prior_HadCM_old_2PIC_SST_D47_monthly = cov_raw_HadCM_old_2PIC_monthly_SST.copy() # Copy covariance matrix to add uncertainty coming from the measurements
cov_prior_HadCM_old_2PIC_SAT_D47_monthly = cov_raw_HadCM_old_2PIC_monthly_SAT.copy() # Copy covariance matrix to add uncertainty coming from the measurements
np.fill_diagonal(cov_prior_HadCM_old_2PIC_SST_D47_monthly, np.diagonal(cov_raw_HadCM_old_2PIC_monthly_SST) + HadCM_old_2PIC_calibration_variances_SST)  # Add diagonal terms for measurement uncertainties (which have no covariance between models)
np.fill_diagonal(cov_prior_HadCM_old_2PIC_SAT_D47_monthly, np.diagonal(cov_raw_HadCM_old_2PIC_monthly_SAT) + HadCM_old_2PIC_calibration_variances_SAT)  # Add diagonal terms for measurement uncertainties (which have no covariance between models)

cov_raw_HadCM_old_4PIC_monthly_SST = np.cov(Lutetian_HadCM_old_4PIC_model[[f"{month}_SST_D47" for month in months]].dropna(), rowvar = False)  # Compute the covariance matrix for the raw data (without measurement uncertainty)
cov_raw_HadCM_old_4PIC_monthly_SAT = np.cov(Lutetian_HadCM_old_4PIC_model[[f"{month}_SAT_D47" for month in months]].dropna(), rowvar = False)  # Compute the covariance matrix for the raw data (without measurement uncertainty)
cov_raw_HadCM_old_4PIC_monthly_d18Ow = np.cov(Lutetian_HadCM_old_4PIC_model[[f"{month}_SSS_d18Ow" for month in months]].dropna(), rowvar = False)  # Compute the covariance matrix for the raw data (without measurement uncertainty)
cov_raw_HadCM_old_4PIC_monthly_d18Oc = np.cov(Lutetian_HadCM_old_4PIC_model[[f"{month}_d18Oc" for month in months]].dropna(), rowvar = False)  # Compute the covariance matrix for the raw data (without measurement uncertainty)
cov_prior_HadCM_old_4PIC_SST_D47_monthly = cov_raw_HadCM_old_4PIC_monthly_SST.copy() # Copy covariance matrix to add uncertainty coming from the measurements
cov_prior_HadCM_old_4PIC_SAT_D47_monthly = cov_raw_HadCM_old_4PIC_monthly_SAT.copy() # Copy covariance matrix to add uncertainty coming from the measurements
np.fill_diagonal(cov_prior_HadCM_old_4PIC_SST_D47_monthly, np.diagonal(cov_raw_HadCM_old_4PIC_monthly_SST) + HadCM_old_4PIC_calibration_variances_SST)  # Add diagonal terms for measurement uncertainties (which have no covariance between models)
np.fill_diagonal(cov_prior_HadCM_old_4PIC_SAT_D47_monthly, np.diagonal(cov_raw_HadCM_old_4PIC_monthly_SAT) + HadCM_old_4PIC_calibration_variances_SAT)  # Add diagonal terms for measurement uncertainties (which have no covariance between models)

# Store copy of original prior means to keep when later updating the prior
mu_prior_CESM_4PIC_SST_D47_monthly_original, cov_prior_CESM_4PIC_SST_D47_monthly_original = mu_prior_CESM_4PIC_SST_D47_monthly.copy(), cov_prior_CESM_4PIC_SST_D47_monthly.copy()
mu_prior_CESM_4PIC_SAT_D47_monthly_original, cov_prior_CESM_4PIC_SAT_D47_monthly_original = mu_prior_CESM_4PIC_SAT_D47_monthly.copy(), cov_prior_CESM_4PIC_SAT_D47_monthly.copy()
mu_prior_CESM_4PIC_SSS_d18Ow_monthly_original, cov_prior_CESM_4PIC_SSS_d18Ow_monthly_original = mu_prior_CESM_4PIC_SSS_d18Ow_monthly.copy(), cov_raw_CESM_4PIC_monthly_d18Ow.copy()
mu_prior_CESM_4PIC_d18Oc_monthly_original, cov_prior_CESM_4PIC_d18Oc_monthly_original = mu_prior_CESM_4PIC_d18Oc_monthly.copy(), cov_raw_CESM_4PIC_monthly_d18Oc.copy()

mu_prior_CESM_2PIC_SST_D47_monthly_original, cov_prior_CESM_2PIC_SST_D47_monthly_original = mu_prior_CESM_2PIC_SST_D47_monthly.copy(), cov_prior_CESM_2PIC_SST_D47_monthly.copy()
mu_prior_CESM_2PIC_SAT_D47_monthly_original, cov_prior_CESM_2PIC_SAT_D47_monthly_original = mu_prior_CESM_2PIC_SAT_D47_monthly.copy(), cov_prior_CESM_2PIC_SAT_D47_monthly.copy()
mu_prior_CESM_2PIC_SSS_d18Ow_monthly_original, cov_prior_CESM_2PIC_SSS_d18Ow_monthly_original = mu_prior_CESM_2PIC_SSS_d18Ow_monthly.copy(), cov_raw_CESM_2PIC_monthly_d18Ow.copy()
mu_prior_CESM_2PIC_d18Oc_monthly_original, cov_prior_CESM_2PIC_d18Oc_monthly_original = mu_prior_CESM_2PIC_d18Oc_monthly.copy(), cov_raw_CESM_2PIC_monthly_d18Oc.copy()

mu_prior_HadCM_new_1PIC_SST_D47_monthly_original, cov_prior_HadCM_new_1PIC_SST_D47_monthly_original = mu_prior_HadCM_new_1PIC_SST_D47_monthly.copy(), cov_prior_HadCM_new_1PIC_SST_D47_monthly.copy()
mu_prior_HadCM_new_1PIC_SAT_D47_monthly_original, cov_prior_HadCM_new_1PIC_SAT_D47_monthly_original = mu_prior_HadCM_new_1PIC_SAT_D47_monthly.copy(), cov_prior_HadCM_new_1PIC_SAT_D47_monthly.copy()
mu_prior_HadCM_new_1PIC_SSS_d18Ow_monthly_original, cov_prior_HadCM_new_1PIC_SSS_d18Ow_monthly_original = mu_prior_HadCM_new_1PIC_SSS_d18Ow_monthly.copy(), cov_raw_HadCM_new_1PIC_monthly_d18Ow.copy()
mu_prior_HadCM_new_1PIC_d18Oc_monthly_original, cov_prior_HadCM_new_1PIC_d18Oc_monthly_original = mu_prior_HadCM_new_1PIC_d18Oc_monthly.copy(), cov_raw_HadCM_new_1PIC_monthly_d18Oc.copy()

mu_prior_HadCM_new_2PIC_SST_D47_monthly_original, cov_prior_HadCM_new_2PIC_SST_D47_monthly_original = mu_prior_HadCM_new_2PIC_SST_D47_monthly.copy(), cov_prior_HadCM_new_2PIC_SST_D47_monthly.copy()
mu_prior_HadCM_new_2PIC_SAT_D47_monthly_original, cov_prior_HadCM_new_2PIC_SAT_D47_monthly_original = mu_prior_HadCM_new_2PIC_SAT_D47_monthly.copy(), cov_prior_HadCM_new_2PIC_SAT_D47_monthly.copy()
mu_prior_HadCM_new_2PIC_SSS_d18Ow_monthly_original, cov_prior_HadCM_new_2PIC_SSS_d18Ow_monthly_original = mu_prior_HadCM_new_2PIC_SSS_d18Ow_monthly.copy(), cov_raw_HadCM_new_2PIC_monthly_d18Ow.copy()
mu_prior_HadCM_new_2PIC_d18Oc_monthly_original, cov_prior_HadCM_new_2PIC_d18Oc_monthly_original = mu_prior_HadCM_new_2PIC_d18Oc_monthly.copy(), cov_raw_HadCM_new_2PIC_monthly_d18Oc.copy()

mu_prior_HadCM_new_1056ppm_SST_D47_monthly_original, cov_prior_HadCM_new_1056ppm_SST_D47_monthly_original = mu_prior_HadCM_new_1056ppm_SST_D47_monthly.copy(), cov_prior_HadCM_new_1056ppm_SST_D47_monthly.copy()
mu_prior_HadCM_new_1056ppm_SAT_D47_monthly_original, cov_prior_HadCM_new_1056ppm_SAT_D47_monthly_original = mu_prior_HadCM_new_1056ppm_SAT_D47_monthly.copy(), cov_prior_HadCM_new_1056ppm_SAT_D47_monthly.copy()
mu_prior_HadCM_new_1056ppm_SSS_d18Ow_monthly_original, cov_prior_HadCM_new_1056ppm_SSS_d18Ow_monthly_original = mu_prior_HadCM_new_1056ppm_SSS_d18Ow_monthly.copy(), cov_raw_HadCM_new_1056ppm_monthly_d18Ow.copy()
mu_prior_HadCM_new_1056ppm_d18Oc_monthly_original, cov_prior_HadCM_new_1056ppm_d18Oc_monthly_original = mu_prior_HadCM_new_1056ppm_d18Oc_monthly.copy(), cov_raw_HadCM_new_1056ppm_monthly_d18Oc.copy()

mu_prior_HadCM_old_2PIC_SST_D47_monthly_original, cov_prior_HadCM_old_2PIC_SST_D47_monthly_original = mu_prior_HadCM_old_2PIC_SST_D47_monthly.copy(), cov_prior_HadCM_old_2PIC_SST_D47_monthly.copy()
mu_prior_HadCM_old_2PIC_SAT_D47_monthly_original, cov_prior_HadCM_old_2PIC_SAT_D47_monthly_original = mu_prior_HadCM_old_2PIC_SAT_D47_monthly.copy(), cov_prior_HadCM_old_2PIC_SAT_D47_monthly.copy()
mu_prior_HadCM_old_2PIC_SSS_d18Ow_monthly_original, cov_prior_HadCM_old_2PIC_SSS_d18Ow_monthly_original = mu_prior_HadCM_old_2PIC_SSS_d18Ow_monthly.copy(), cov_raw_HadCM_old_2PIC_monthly_d18Ow.copy()
mu_prior_HadCM_old_2PIC_d18Oc_monthly_original, cov_prior_HadCM_old_2PIC_d18Oc_monthly_original = mu_prior_HadCM_old_2PIC_d18Oc_monthly.copy(), cov_raw_HadCM_old_2PIC_monthly_d18Oc.copy()

mu_prior_HadCM_old_4PIC_SST_D47_monthly_original, cov_prior_HadCM_old_4PIC_SST_D47_monthly_original = mu_prior_HadCM_old_4PIC_SST_D47_monthly.copy(), cov_prior_HadCM_old_4PIC_SST_D47_monthly.copy()
mu_prior_HadCM_old_4PIC_SAT_D47_monthly_original, cov_prior_HadCM_old_4PIC_SAT_D47_monthly_original = mu_prior_HadCM_old_4PIC_SAT_D47_monthly.copy(), cov_prior_HadCM_old_4PIC_SAT_D47_monthly.copy()
mu_prior_HadCM_old_4PIC_SSS_d18Ow_monthly_original, cov_prior_HadCM_old_4PIC_SSS_d18Ow_monthly_original = mu_prior_HadCM_old_4PIC_SSS_d18Ow_monthly.copy(), cov_raw_HadCM_old_4PIC_monthly_d18Ow.copy()
mu_prior_HadCM_old_4PIC_d18Oc_monthly_original, cov_prior_HadCM_old_4PIC_d18Oc_monthly_original = mu_prior_HadCM_old_4PIC_d18Oc_monthly.copy(), cov_raw_HadCM_old_4PIC_monthly_d18Oc.copy()

# Extract the standard deviations (uncertainty) from the covariance matrix
std_prior_CESM_4PIC_SST_D47_monthly = np.sqrt(np.diag(cov_prior_CESM_4PIC_SST_D47_monthly))
std_prior_CESM_4PIC_SAT_D47_monthly = np.sqrt(np.diag(cov_prior_CESM_4PIC_SAT_D47_monthly))
std_prior_CESM_4PIC_SSS_d18Ow_monthly = np.sqrt(np.diag(cov_raw_CESM_4PIC_monthly_d18Ow))
std_prior_CESM_4PIC_d18Oc_monthly = np.sqrt(np.diag(cov_raw_CESM_4PIC_monthly_d18Oc))

std_prior_CESM_2PIC_SST_D47_monthly = np.sqrt(np.diag(cov_prior_CESM_2PIC_SST_D47_monthly))
std_prior_CESM_2PIC_SAT_D47_monthly = np.sqrt(np.diag(cov_prior_CESM_2PIC_SAT_D47_monthly))
std_prior_CESM_2PIC_SSS_d18Ow_monthly = np.sqrt(np.diag(cov_raw_CESM_2PIC_monthly_d18Ow))
std_prior_CESM_2PIC_d18Oc_monthly = np.sqrt(np.diag(cov_raw_CESM_2PIC_monthly_d18Oc))

std_prior_HadCM_new_1PIC_SST_D47_monthly = np.sqrt(np.diag(cov_prior_HadCM_new_1PIC_SST_D47_monthly))
std_prior_HadCM_new_1PIC_SAT_D47_monthly = np.sqrt(np.diag(cov_prior_HadCM_new_1PIC_SAT_D47_monthly))
std_prior_HadCM_new_1PIC_SSS_d18Ow_monthly = np.sqrt(np.diag(cov_raw_HadCM_new_1PIC_monthly_d18Ow))
std_prior_HadCM_new_1PIC_d18Oc_monthly = np.sqrt(np.diag(cov_raw_HadCM_new_1PIC_monthly_d18Oc))

std_prior_HadCM_new_2PIC_SST_D47_monthly = np.sqrt(np.diag(cov_prior_HadCM_new_2PIC_SST_D47_monthly))
std_prior_HadCM_new_2PIC_SAT_D47_monthly = np.sqrt(np.diag(cov_prior_HadCM_new_2PIC_SAT_D47_monthly))
std_prior_HadCM_new_2PIC_SSS_d18Ow_monthly = np.sqrt(np.diag(cov_raw_HadCM_new_2PIC_monthly_d18Ow))
std_prior_HadCM_new_2PIC_d18Oc_monthly = np.sqrt(np.diag(cov_raw_HadCM_new_2PIC_monthly_d18Oc))

std_prior_HadCM_new_1056ppm_SST_D47_monthly = np.sqrt(np.diag(cov_prior_HadCM_new_1056ppm_SST_D47_monthly))
std_prior_HadCM_new_1056ppm_SAT_D47_monthly = np.sqrt(np.diag(cov_prior_HadCM_new_1056ppm_SAT_D47_monthly))
std_prior_HadCM_new_1056ppm_SSS_d18Ow_monthly = np.sqrt(np.diag(cov_raw_HadCM_new_1056ppm_monthly_d18Ow))
std_prior_HadCM_new_1056ppm_d18Oc_monthly = np.sqrt(np.diag(cov_raw_HadCM_new_1056ppm_monthly_d18Oc))

std_prior_HadCM_old_2PIC_SST_D47_monthly = np.sqrt(np.diag(cov_prior_HadCM_old_2PIC_SST_D47_monthly))
std_prior_HadCM_old_2PIC_SAT_D47_monthly = np.sqrt(np.diag(cov_prior_HadCM_old_2PIC_SAT_D47_monthly))
std_prior_HadCM_old_2PIC_SSS_d18Ow_monthly = np.sqrt(np.diag(cov_raw_HadCM_old_2PIC_monthly_d18Ow))
std_prior_HadCM_old_2PIC_d18Oc_monthly = np.sqrt(np.diag(cov_raw_HadCM_old_2PIC_monthly_d18Oc))

std_prior_HadCM_old_4PIC_SST_D47_monthly = np.sqrt(np.diag(cov_prior_HadCM_old_4PIC_SST_D47_monthly))
std_prior_HadCM_old_4PIC_SAT_D47_monthly = np.sqrt(np.diag(cov_prior_HadCM_old_4PIC_SAT_D47_monthly))
std_prior_HadCM_old_4PIC_SSS_d18Ow_monthly = np.sqrt(np.diag(cov_raw_HadCM_old_4PIC_monthly_d18Ow))
std_prior_HadCM_old_4PIC_d18Oc_monthly = np.sqrt(np.diag(cov_raw_HadCM_old_4PIC_monthly_d18Oc))

# Print some the results as a check
print("Prior D47 estimates from SST in CESM model with 4x preindustrial pCO2 (weighted mean):")
print(mu_prior_CESM_4PIC_SST_D47_monthly)
print("Prior D47 estimates from SST in CESM model with 2x preindustrial pCO2 (weighted mean):")
print(mu_prior_CESM_2PIC_SST_D47_monthly)
print("Prior D47 estimates from SST in CESM model with 4x preindustrial pCO2 (weighted covariance matrix):")
print(std_prior_CESM_4PIC_SST_D47_monthly)
print("Prior D47 estimates from SST in CESM model with 2x preindustrial pCO2 (weighted covariance matrix):")
print(std_prior_CESM_2PIC_SST_D47_monthly)
print("Prior D47 estimates from SAT in CESM model with 4x preindustrial pCO2 (weighted mean):")
print(mu_prior_CESM_4PIC_SAT_D47_monthly)
print("Prior D47 estimates from SAT in CESM model with 2x preindustrial pCO2 (weighted mean):")
print(mu_prior_CESM_2PIC_SAT_D47_monthly)
print("Prior D47 estimates from SAT in CESM model with 4x preindustrial pCO2 (weighted covariance matrix):")
print(std_prior_CESM_4PIC_SAT_D47_monthly)
print("Prior D47 estimates from SAT in CESM model with 2x preindustrial pCO2 (weighted covariance matrix):")
print(std_prior_CESM_2PIC_SAT_D47_monthly)
print("Prior d18Ow estimates from SSS in CESM model with 4x preindustrial pCO2 (weighted mean):")
print(mu_prior_CESM_4PIC_SSS_d18Ow_monthly)
print("Prior d18Ow estimates from SSS in CESM model with 2x preindustrial pCO2 (weighted mean):")
print(mu_prior_CESM_2PIC_SSS_d18Ow_monthly)
print("Prior d18Ow estimates from SSS in CESM model with 4x preindustrial pCO2 (weighted covariance matrix):")
print(std_prior_CESM_4PIC_SSS_d18Ow_monthly)
print("Prior d18Ow estimates from SSS in CESM model with 2x preindustrial pCO2 (weighted covariance matrix):")
print(std_prior_CESM_2PIC_SSS_d18Ow_monthly)
print("Prior d18Oc estimates from SST and d18Ow in CESM model with 4x preindustrial pCO2 (weighted mean):")
print(mu_prior_CESM_4PIC_d18Oc_monthly)
print("Prior d18Oc estimates from SST and d18Ow in CESM model with 2x preindustrial pCO2 (weighted mean):")
print(mu_prior_CESM_2PIC_d18Oc_monthly)
print("Prior d18Oc estimates from SST and d18Ow in CESM model with 4x preindustrial pCO2 (weighted covariance matrix):")
print(std_prior_CESM_4PIC_d18Oc_monthly)
print("Prior d18Oc estimates from SST and d18Ow in CESM model with 2x preindustrial pCO2 (weighted covariance matrix):")
print(std_prior_CESM_2PIC_d18Oc_monthly)
Prior D47 estimates from SST in CESM model with 4x preindustrial pCO2 (weighted mean):
[0.59656789 0.59858139 0.59867924 0.59638204 0.58858685 0.57705811
 0.56727922 0.56351195 0.5670409  0.57510508 0.58376364 0.59171077]
Prior D47 estimates from SST in CESM model with 2x preindustrial pCO2 (weighted mean):
[0.60489442 0.60666426 0.60683094 0.60417118 0.59618643 0.58512465
 0.5755485  0.57189757 0.57548974 0.58366672 0.59236182 0.60038379]
Prior D47 estimates from SST in CESM model with 4x preindustrial pCO2 (weighted covariance matrix):
[0.00890411 0.00944467 0.00936157 0.00859554 0.00739686 0.00653869
 0.00575527 0.00534817 0.00493985 0.00482531 0.00621776 0.00782822]
Prior D47 estimates from SST in CESM model with 2x preindustrial pCO2 (weighted covariance matrix):
[0.01009378 0.01057793 0.01042161 0.00955301 0.00826056 0.00738042
 0.0066458  0.00598658 0.00544544 0.0055813  0.00709986 0.00884544]
Prior D47 estimates from SAT in CESM model with 4x preindustrial pCO2 (weighted mean):
[0.62006985 0.61787124 0.61269573 0.60374682 0.58703137 0.57294061
 0.56290407 0.56283341 0.57307851 0.59111554 0.60696862 0.61709809]
Prior D47 estimates from SAT in CESM model with 2x preindustrial pCO2 (weighted mean):
[0.63053005 0.62879279 0.62393577 0.61368013 0.59859233 0.5867432
 0.57737842 0.57609754 0.58529981 0.60308352 0.61883373 0.62866658]
Prior D47 estimates from SAT in CESM model with 4x preindustrial pCO2 (weighted covariance matrix):
[0.01142741 0.01018869 0.0090148  0.00801557 0.00738831 0.00779214
 0.00785649 0.00725533 0.00718243 0.00905268 0.01135674 0.01208698]
Prior D47 estimates from SAT in CESM model with 2x preindustrial pCO2 (weighted covariance matrix):
[0.01208732 0.0110329  0.00996397 0.00848212 0.00760235 0.00785875
 0.00842843 0.00790733 0.0080588  0.01021703 0.01233193 0.013147  ]
Prior d18Ow estimates from SSS in CESM model with 4x preindustrial pCO2 (weighted mean):
[0.15012888 0.14789931 0.14304506 0.13812488 0.13628413 0.13603111
 0.13019769 0.12741946 0.12790254 0.13567087 0.14471762 0.15102158]
Prior d18Ow estimates from SSS in CESM model with 2x preindustrial pCO2 (weighted mean):
[0.17535131 0.16860723 0.16122267 0.15074699 0.14675776 0.14626297
 0.14379877 0.1478799  0.15903551 0.1703924  0.17741777 0.1799819 ]
Prior d18Ow estimates from SSS in CESM model with 4x preindustrial pCO2 (weighted covariance matrix):
[0.82621873 0.81838544 0.81441585 0.81562978 0.82277265 0.83136673
 0.84163147 0.85144349 0.85933502 0.86079046 0.85069356 0.83659413]
Prior d18Ow estimates from SSS in CESM model with 2x preindustrial pCO2 (weighted covariance matrix):
[0.78365866 0.77611692 0.77221433 0.7756884  0.78626843 0.79651165
 0.80712123 0.81866035 0.82756578 0.82843509 0.81688634 0.79756155]
Prior d18Oc estimates from SST and d18Ow in CESM model with 4x preindustrial pCO2 (weighted mean):
[-0.87134431 -0.71613404 -0.7139883  -0.89894578 -1.51047705 -2.43504627
 -3.25136303 -3.57317763 -3.27234184 -2.5945588  -1.88634864 -1.25084057]
Prior d18Oc estimates from SST and d18Ow in CESM model with 2x preindustrial pCO2 (weighted mean):
[-0.20804548 -0.07873241 -0.07509482 -0.29063799 -0.90690032 -1.77413891
 -2.55085312 -2.84797432 -2.54024627 -1.8689654  -1.17633926 -0.55155968]
Prior d18Oc estimates from SST and d18Ow in CESM model with 4x preindustrial pCO2 (weighted covariance matrix):
[0.43074162 0.4079074  0.39792762 0.39889866 0.41067086 0.41700845
 0.43048772 0.48872905 0.56171093 0.58936283 0.51749387 0.46825537]
Prior d18Oc estimates from SST and d18Ow in CESM model with 2x preindustrial pCO2 (weighted covariance matrix):
[0.40225003 0.393072   0.38290499 0.36843204 0.36587289 0.37604721
 0.38016149 0.44783066 0.51482087 0.52320248 0.45863081 0.42027637]

Plot the monthly prior for model SST- and SAT-derived D47 values, model SSS-derived carbonate d18O values and precipitation with propagated uncertainty¶

In [38]:
# Plot monthly prior distribution
fig, axes = plt.subplots(4, 7, figsize=(20, 10), sharey="row", sharex="col")  # Adjust the figure to have 2x2 grid

# Start with priors for CESM model with 4x pre-industrial CO2

# Plot the prior distribution for SST
axes[0, 0].plot(months_scale, mu_prior_CESM_4PIC_SST_D47_monthly, label='Prior SST Mean', color='b', marker='o')
axes[0, 0].fill_between(months_scale,
                        mu_prior_CESM_4PIC_SST_D47_monthly - stats.t.ppf(1 - 0.025, n_models_CESM_4PIC_monthly) * std_prior_CESM_4PIC_SST_D47_monthly / np.sqrt(n_models_CESM_4PIC_monthly),
                        mu_prior_CESM_4PIC_SST_D47_monthly + stats.t.ppf(1 - 0.025, n_models_CESM_4PIC_monthly) * std_prior_CESM_4PIC_SST_D47_monthly / np.sqrt(n_models_CESM_4PIC_monthly),
                        color='b', alpha=0.2, label='95% Confidence Interval')
axes[0, 0].set_xticks(months_scale)
axes[0, 0].set_xticklabels(month_names, rotation=45, ha="right")
axes[0, 0].set_title('CESM\n4x preindustrial pCO2\nSST D47 values')
axes[0, 0].set_xlabel('Month')
axes[0, 0].set_ylabel('D47 value')
# axes[0, 0].legend()
axes[0, 0].grid(True)

# Plot the prior distribution for SAT
axes[1, 0].plot(months_scale, mu_prior_CESM_4PIC_SAT_D47_monthly, label='Prior SAT Mean', color='r', marker='o')
axes[1, 0].fill_between(months_scale,
                        mu_prior_CESM_4PIC_SAT_D47_monthly - stats.t.ppf(1 - 0.025, n_models_CESM_4PIC_monthly) * std_prior_CESM_4PIC_SAT_D47_monthly / np.sqrt(n_models_CESM_4PIC_monthly),
                        mu_prior_CESM_4PIC_SAT_D47_monthly + stats.t.ppf(1 - 0.025, n_models_CESM_4PIC_monthly) * std_prior_CESM_4PIC_SAT_D47_monthly / np.sqrt(n_models_CESM_4PIC_monthly),
                        color='r', alpha=0.2, label='95% Confidence Interval')
axes[1, 0].set_xticks(months_scale)
axes[1, 0].set_xticklabels(month_names, rotation=45, ha="right")
axes[1, 0].set_title('SAT D47 values')
axes[1, 0].set_xlabel('Month')
axes[1, 0].set_ylabel('D47 value')
# axes[1, 0].legend()
axes[1, 0].grid(True)

# Plot the prior distribution for d18Oc
axes[2, 0].plot(months_scale, mu_prior_CESM_4PIC_d18Oc_monthly, label='Prior d18Oc Mean', color='purple', marker='o')
axes[2, 0].fill_between(months_scale,
                        mu_prior_CESM_4PIC_d18Oc_monthly - stats.t.ppf(1 - 0.025, n_models_CESM_4PIC_monthly) * std_prior_CESM_4PIC_d18Oc_monthly / np.sqrt(n_models_CESM_4PIC_monthly),
                        mu_prior_CESM_4PIC_d18Oc_monthly + stats.t.ppf(1 - 0.025, n_models_CESM_4PIC_monthly) * std_prior_CESM_4PIC_d18Oc_monthly / np.sqrt(n_models_CESM_4PIC_monthly),
                        color='purple', alpha=0.2, label='95% Confidence Interval')
axes[2, 0].set_xticks(months_scale)
axes[2, 0].set_xticklabels(month_names, rotation=45, ha="right")
axes[2, 0].set_title('d18Oc values')
axes[2, 0].set_xlabel('Month')
axes[2, 0].set_ylabel('d18Oc value')
# axes[2, 0].legend()
axes[2, 0].grid(True)

# Plot the prior distribution for precipitation
axes[3, 0].plot(months_scale, mu_prior_CESM_4PIC_precip_monthly, label='Prior Precipitation Mean', color='teal', marker='o')
axes[3, 0].fill_between(months_scale,
                        mu_prior_CESM_4PIC_precip_monthly - stats.t.ppf(1 - 0.025, n_models_CESM_4PIC_monthly) * std_prior_CESM_4PIC_precip_monthly / np.sqrt(n_models_CESM_4PIC_monthly),
                        mu_prior_CESM_4PIC_precip_monthly + stats.t.ppf(1 - 0.025, n_models_CESM_4PIC_monthly) * std_prior_CESM_4PIC_precip_monthly / np.sqrt(n_models_CESM_4PIC_monthly),
                        color='teal', alpha=0.2, label='95% Confidence Interval')
axes[3, 0].set_xticks(months_scale)
axes[3, 0].set_xticklabels(month_names, rotation=45, ha="right")
axes[3, 0].set_title('Precipitation values')
axes[3, 0].set_xlabel('Month')
axes[3, 0].set_ylabel('Precipitation (mm/day)')
# axes[3, 0].legend()
axes[3, 0].grid(True)

# Now for priors for CESM model with 2x pre-industrial CO2
# Plot the prior distribution for SST
axes[0, 1].plot(months_scale, mu_prior_CESM_2PIC_SST_D47_monthly, label='Prior SST Mean', color='b', marker='o')
axes[0, 1].fill_between(months_scale,
                        mu_prior_CESM_2PIC_SST_D47_monthly - stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_SST_D47_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
                        mu_prior_CESM_2PIC_SST_D47_monthly + stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_SST_D47_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
                        color='b', alpha=0.2, label='95% Confidence Interval')
axes[0, 1].set_xticks(months_scale)
axes[0, 1].set_xticklabels(month_names, rotation=45, ha="right")
axes[0, 1].set_title('CESM\n2x preindustrial pCO2\nSST D47 values')
axes[0, 1].set_xlabel('Month')
axes[0, 1].set_ylabel('D47 value')
# axes[0, 1].legend()
axes[0, 1].grid(True)

# Plot the prior distribution for SAT
axes[1, 1].plot(months_scale, mu_prior_CESM_2PIC_SAT_D47_monthly, label='Prior SAT Mean', color='r', marker='o')
axes[1, 1].fill_between(months_scale,
                        mu_prior_CESM_2PIC_SAT_D47_monthly - stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_SAT_D47_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
                        mu_prior_CESM_2PIC_SAT_D47_monthly + stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_SAT_D47_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
                        color='r', alpha=0.2, label='95% Confidence Interval')
axes[1, 1].set_xticks(months_scale)
axes[1, 1].set_xticklabels(month_names, rotation=45, ha="right")
axes[1, 1].set_title('SAT D47 values')
axes[1, 1].set_xlabel('Month')
axes[1, 1].set_ylabel('D47 value')
# axes[1, 1].legend()
axes[1, 1].grid(True)

# Plot the prior distribution for d18Oc
axes[2, 1].plot(months_scale, mu_prior_CESM_2PIC_d18Oc_monthly, label='Prior d18Oc Mean', color='purple', marker='o')
axes[2, 1].fill_between(months_scale,
                        mu_prior_CESM_2PIC_d18Oc_monthly - stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_d18Oc_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
                        mu_prior_CESM_2PIC_d18Oc_monthly + stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_d18Oc_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
                        color='purple', alpha=0.2, label='95% Confidence Interval')
axes[2, 1].set_xticks(months_scale)
axes[2, 1].set_xticklabels(month_names, rotation=45, ha="right")
axes[2, 1].set_title('d18Oc values')
axes[2, 1].set_xlabel('Month')
axes[2, 1].set_ylabel('d18Oc value')
# axes[2, 1].legend()
axes[2, 1].grid(True)

# Plot the prior distribution for precipitation
axes[3, 1].plot(months_scale, mu_prior_CESM_2PIC_precip_monthly, label='Prior Precipitation Mean', color='teal', marker='o')
axes[3, 1].fill_between(months_scale,
                        mu_prior_CESM_2PIC_precip_monthly - stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_precip_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
                        mu_prior_CESM_2PIC_precip_monthly + stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_precip_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
                        color='teal', alpha=0.2, label='95% Confidence Interval')
axes[3, 1].set_xticks(months_scale)
axes[3, 1].set_xticklabels(month_names, rotation=45, ha="right")
axes[3, 1].set_title('Precipitation values')
axes[3, 1].set_xlabel('Month')
axes[3, 1].set_ylabel('Precipitation (mm/day)')
# axes[3, 1].legend()
axes[3, 1].grid(True)

# Now for priors for HadCM model with 1x pre-industrial CO2
# Plot the prior distribution for SST
axes[0, 2].plot(months_scale, mu_prior_HadCM_new_1PIC_SST_D47_monthly, label='Prior SST Mean', color='b', marker='o')
axes[0, 2].fill_between(months_scale,
                        mu_prior_HadCM_new_1PIC_SST_D47_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_1PIC_monthly) * std_prior_HadCM_new_1PIC_SST_D47_monthly / np.sqrt(n_models_HadCM_new_1PIC_monthly),
                        mu_prior_HadCM_new_1PIC_SST_D47_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_1PIC_monthly) * std_prior_HadCM_new_1PIC_SST_D47_monthly / np.sqrt(n_models_HadCM_new_1PIC_monthly),
                        color='b', alpha=0.2, label='95% Confidence Interval')
axes[0, 2].set_xticks(months_scale)
axes[0, 2].set_xticklabels(month_names, rotation=45, ha="right")
axes[0, 2].set_title('HadCM (new)\n1x preindustrial pCO2\nSST D47 values')
axes[0, 2].set_xlabel('Month')
axes[0, 2].set_ylabel('D47 value')
# axes[0, 2].legend()
axes[0, 2].grid(True)

# Plot the prior distribution for SAT
axes[1, 2].plot(months_scale, mu_prior_HadCM_new_1PIC_SAT_D47_monthly, label='Prior SAT Mean', color='r', marker='o')
axes[1, 2].fill_between(months_scale,
                        mu_prior_HadCM_new_1PIC_SAT_D47_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_1PIC_monthly) * std_prior_HadCM_new_1PIC_SAT_D47_monthly / np.sqrt(n_models_HadCM_new_1PIC_monthly),
                        mu_prior_HadCM_new_1PIC_SAT_D47_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_1PIC_monthly) * std_prior_HadCM_new_1PIC_SAT_D47_monthly / np.sqrt(n_models_HadCM_new_1PIC_monthly),
                        color='r', alpha=0.2, label='95% Confidence Interval')
axes[1, 2].set_xticks(months_scale)
axes[1, 2].set_xticklabels(month_names, rotation=45, ha="right")
axes[1, 2].set_title('SAT D47 values')
axes[1, 2].set_xlabel('Month')
axes[1, 2].set_ylabel('D47 value')
# axes[1, 2].legend()
axes[1, 2].grid(True)

# Plot the prior distribution for d18Oc
axes[2, 2].plot(months_scale, mu_prior_HadCM_new_1PIC_d18Oc_monthly, label='Prior d18Oc Mean', color='purple', marker='o')
axes[2, 2].fill_between(months_scale,
                        mu_prior_HadCM_new_1PIC_d18Oc_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_1PIC_monthly) * std_prior_HadCM_new_1PIC_d18Oc_monthly / np.sqrt(n_models_HadCM_new_1PIC_monthly),
                        mu_prior_HadCM_new_1PIC_d18Oc_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_1PIC_monthly) * std_prior_HadCM_new_1PIC_d18Oc_monthly / np.sqrt(n_models_HadCM_new_1PIC_monthly),
                        color='purple', alpha=0.2, label='95% Confidence Interval')
axes[2, 2].set_xticks(months_scale)
axes[2, 2].set_xticklabels(month_names, rotation=45, ha="right")
axes[2, 2].set_title('d18Oc values')
axes[2, 2].set_xlabel('Month')
axes[2, 2].set_ylabel('d18Oc value')
# axes[2, 2].legend()
axes[2, 2].grid(True)

# Plot the prior distribution for precipitation
axes[3, 2].plot(months_scale, mu_prior_HadCM_new_1PIC_precip_monthly, label='Prior Precipitation Mean', color='teal', marker='o')
axes[3, 2].fill_between(months_scale,
                        mu_prior_HadCM_new_1PIC_precip_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_1PIC_monthly) * std_prior_HadCM_new_1PIC_precip_monthly / np.sqrt(n_models_HadCM_new_1PIC_monthly),
                        mu_prior_HadCM_new_1PIC_precip_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_1PIC_monthly) * std_prior_HadCM_new_1PIC_precip_monthly / np.sqrt(n_models_HadCM_new_1PIC_monthly),
                        color='teal', alpha=0.2, label='95% Confidence Interval')
axes[3, 2].set_xticks(months_scale)
axes[3, 2].set_xticklabels(month_names, rotation=45, ha="right")
axes[3, 2].set_title('Precipitation values')
axes[3, 2].set_xlabel('Month')
axes[3, 2].set_ylabel('Precipitation (mm/day)')
# axes[3, 2].legend()
axes[3, 2].grid(True)

# Now for priors for HadCM model with 2x pre-industrial CO2
# Plot the prior distribution for SST
axes[0, 3].plot(months_scale, mu_prior_HadCM_new_2PIC_SST_D47_monthly, label='Prior SST Mean', color='b', marker='o')
axes[0, 3].fill_between(months_scale,
                        mu_prior_HadCM_new_2PIC_SST_D47_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_2PIC_monthly) * std_prior_HadCM_new_2PIC_SST_D47_monthly / np.sqrt(n_models_HadCM_new_2PIC_monthly),
                        mu_prior_HadCM_new_2PIC_SST_D47_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_2PIC_monthly) * std_prior_HadCM_new_2PIC_SST_D47_monthly / np.sqrt(n_models_HadCM_new_2PIC_monthly),
                        color='b', alpha=0.2, label='95% Confidence Interval')
axes[0, 3].set_xticks(months_scale)
axes[0, 3].set_xticklabels(month_names, rotation=45, ha="right")
axes[0, 3].set_title('HadCM (new)\n2x preindustrial pCO2\nSST D47 values')
axes[0, 3].set_xlabel('Month')
axes[0, 3].set_ylabel('D47 value')
# axes[0, 3].legend()
axes[0, 3].grid(True)

# Plot the prior distribution for SAT
axes[1, 3].plot(months_scale, mu_prior_HadCM_new_2PIC_SAT_D47_monthly, label='Prior SAT Mean', color='r', marker='o')
axes[1, 3].fill_between(months_scale,
                        mu_prior_HadCM_new_2PIC_SAT_D47_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_2PIC_monthly) * std_prior_HadCM_new_2PIC_SAT_D47_monthly / np.sqrt(n_models_HadCM_new_2PIC_monthly),
                        mu_prior_HadCM_new_2PIC_SAT_D47_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_2PIC_monthly) * std_prior_HadCM_new_2PIC_SAT_D47_monthly / np.sqrt(n_models_HadCM_new_2PIC_monthly),
                        color='r', alpha=0.2, label='95% Confidence Interval')
axes[1, 3].set_xticks(months_scale)
axes[1, 3].set_xticklabels(month_names, rotation=45, ha="right")
axes[1, 3].set_title('SAT D47 values')
axes[1, 3].set_xlabel('Month')
axes[1, 3].set_ylabel('D47 value')
# axes[1, 3].legend()
axes[1, 3].grid(True)

# Plot the prior distribution for d18Oc
axes[2, 3].plot(months_scale, mu_prior_HadCM_new_2PIC_d18Oc_monthly, label='Prior d18Oc Mean', color='purple', marker='o')
axes[2, 3].fill_between(months_scale,
                        mu_prior_HadCM_new_2PIC_d18Oc_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_2PIC_monthly) * std_prior_HadCM_new_2PIC_d18Oc_monthly / np.sqrt(n_models_HadCM_new_2PIC_monthly),
                        mu_prior_HadCM_new_2PIC_d18Oc_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_2PIC_monthly) * std_prior_HadCM_new_2PIC_d18Oc_monthly / np.sqrt(n_models_HadCM_new_2PIC_monthly),
                        color='purple', alpha=0.2, label='95% Confidence Interval')
axes[2, 3].set_xticks(months_scale)
axes[2, 3].set_xticklabels(month_names, rotation=45, ha="right")
axes[2, 3].set_title('d18Oc values')
axes[2, 3].set_xlabel('Month')
axes[2, 3].set_ylabel('d18Oc value')
# axes[2, 3].legend()
axes[2, 3].grid(True)

# Plot the prior distribution for precipitation
axes[3, 3].plot(months_scale, mu_prior_HadCM_new_2PIC_precip_monthly, label='Prior Precipitation Mean', color='teal', marker='o')
axes[3, 3].fill_between(months_scale,
                        mu_prior_HadCM_new_2PIC_precip_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_2PIC_monthly) * std_prior_HadCM_new_2PIC_precip_monthly / np.sqrt(n_models_HadCM_new_2PIC_monthly),
                        mu_prior_HadCM_new_2PIC_precip_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_2PIC_monthly) * std_prior_HadCM_new_2PIC_precip_monthly / np.sqrt(n_models_HadCM_new_2PIC_monthly),
                        color='teal', alpha=0.2, label='95% Confidence Interval')
axes[3, 3].set_xticks(months_scale)
axes[3, 3].set_xticklabels(month_names, rotation=45, ha="right")
axes[3, 3].set_title('Precipitation values')
axes[3, 3].set_xlabel('Month')
axes[3, 3].set_ylabel('Precipitation (mm/day)')
# axes[3, 3].legend()
axes[3, 3].grid(True)

# Now for priors for HadCM model with 1056 ppm CO2
# Plot the prior distribution for SST
axes[0, 4].plot(months_scale, mu_prior_HadCM_new_1056ppm_SST_D47_monthly, label='Prior SST Mean', color='b', marker='o')
axes[0, 4].fill_between(months_scale,
                        mu_prior_HadCM_new_1056ppm_SST_D47_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_1056ppm_monthly) * std_prior_HadCM_new_1056ppm_SST_D47_monthly / np.sqrt(n_models_HadCM_new_1056ppm_monthly),
                        mu_prior_HadCM_new_1056ppm_SST_D47_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_1056ppm_monthly) * std_prior_HadCM_new_1056ppm_SST_D47_monthly / np.sqrt(n_models_HadCM_new_1056ppm_monthly),
                        color='b', alpha=0.2, label='95% Confidence Interval')
axes[0, 4].set_xticks(months_scale)
axes[0, 4].set_xticklabels(month_names, rotation=45, ha="right")
axes[0, 4].set_title('HadCM (new)\n1056 ppm pCO2\nSST D47 values')
axes[0, 4].set_xlabel('Month')
axes[0, 4].set_ylabel('D47 value')
# axes[0, 4].legend()
axes[0, 4].grid(True)

# Plot the prior distribution for SAT
axes[1, 4].plot(months_scale, mu_prior_HadCM_new_1056ppm_SAT_D47_monthly, label='Prior SAT Mean', color='r', marker='o')
axes[1, 4].fill_between(months_scale,
                        mu_prior_HadCM_new_1056ppm_SAT_D47_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_1056ppm_monthly) * std_prior_HadCM_new_1056ppm_SAT_D47_monthly / np.sqrt(n_models_HadCM_new_1056ppm_monthly),
                        mu_prior_HadCM_new_1056ppm_SAT_D47_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_1056ppm_monthly) * std_prior_HadCM_new_1056ppm_SAT_D47_monthly / np.sqrt(n_models_HadCM_new_1056ppm_monthly),
                        color='r', alpha=0.2, label='95% Confidence Interval')
axes[1, 4].set_xticks(months_scale)
axes[1, 4].set_xticklabels(month_names, rotation=45, ha="right")
axes[1, 4].set_title('SAT D47 values')
axes[1, 4].set_xlabel('Month')
axes[1, 4].set_ylabel('D47 value')
# axes[1, 4].legend()
axes[1, 4].grid(True)

# Plot the prior distribution for d18Oc
axes[2, 4].plot(months_scale, mu_prior_HadCM_new_1056ppm_d18Oc_monthly, label='Prior d18Oc Mean', color='purple', marker='o')
axes[2, 4].fill_between(months_scale,
                        mu_prior_HadCM_new_1056ppm_d18Oc_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_1056ppm_monthly) * std_prior_HadCM_new_1056ppm_d18Oc_monthly / np.sqrt(n_models_HadCM_new_1056ppm_monthly),
                        mu_prior_HadCM_new_1056ppm_d18Oc_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_1056ppm_monthly) * std_prior_HadCM_new_1056ppm_d18Oc_monthly / np.sqrt(n_models_HadCM_new_1056ppm_monthly),
                        color='purple', alpha=0.2, label='95% Confidence Interval')
axes[2, 4].set_xticks(months_scale)
axes[2, 4].set_xticklabels(month_names, rotation=45, ha="right")
axes[2, 4].set_title('d18Oc values')
axes[2, 4].set_xlabel('Month')
axes[2, 4].set_ylabel('d18Oc value')
# axes[2, 4].legend()
axes[2, 4].grid(True)

# Plot the prior distribution for precipitation
axes[3, 4].plot(months_scale, mu_prior_HadCM_new_1056ppm_precip_monthly, label='Prior Precipitation Mean', color='teal', marker='o')
axes[3, 4].fill_between(months_scale,
                        mu_prior_HadCM_new_1056ppm_precip_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_1056ppm_monthly) * std_prior_HadCM_new_1056ppm_precip_monthly / np.sqrt(n_models_HadCM_new_1056ppm_monthly),
                        mu_prior_HadCM_new_1056ppm_precip_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_1056ppm_monthly) * std_prior_HadCM_new_1056ppm_precip_monthly / np.sqrt(n_models_HadCM_new_1056ppm_monthly),
                        color='teal', alpha=0.2, label='95% Confidence Interval')
axes[3, 4].set_xticks(months_scale)
axes[3, 4].set_xticklabels(month_names, rotation=45, ha="right")
axes[3, 4].set_title('Precipitation values')
axes[3, 4].set_xlabel('Month')
axes[3, 4].set_ylabel('Precipitation (mm/day)')
# axes[3, 4].legend()
axes[3, 4].grid(True)

# Now for priors for old HadCM model with 2x preindustrial CO2
# Plot the prior distribution for SST
axes[0, 5].plot(months_scale, mu_prior_HadCM_old_2PIC_SST_D47_monthly, label='Prior SST Mean', color='b', marker='o')
axes[0, 5].fill_between(months_scale,
                        mu_prior_HadCM_old_2PIC_SST_D47_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_old_2PIC_monthly) * std_prior_HadCM_old_2PIC_SST_D47_monthly / np.sqrt(n_models_HadCM_old_2PIC_monthly),
                        mu_prior_HadCM_old_2PIC_SST_D47_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_old_2PIC_monthly) * std_prior_HadCM_old_2PIC_SST_D47_monthly / np.sqrt(n_models_HadCM_old_2PIC_monthly),
                        color='b', alpha=0.2, label='95% Confidence Interval')
axes[0, 5].set_xticks(months_scale)
axes[0, 5].set_xticklabels(month_names, rotation=45, ha="right")
axes[0, 5].set_title('HadCM (old)\n2x preindustrial pCO2\nSST D47 values')
axes[0, 5].set_xlabel('Month')
axes[0, 5].set_ylabel('D47 value')
# axes[0, 5].legend()
axes[0, 5].grid(True)

# Plot the prior distribution for SAT
axes[1, 5].plot(months_scale, mu_prior_HadCM_old_2PIC_SAT_D47_monthly, label='Prior SAT Mean', color='r', marker='o')
axes[1, 5].fill_between(months_scale,
                        mu_prior_HadCM_old_2PIC_SAT_D47_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_old_2PIC_monthly) * std_prior_HadCM_old_2PIC_SAT_D47_monthly / np.sqrt(n_models_HadCM_old_2PIC_monthly),
                        mu_prior_HadCM_old_2PIC_SAT_D47_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_old_2PIC_monthly) * std_prior_HadCM_old_2PIC_SAT_D47_monthly / np.sqrt(n_models_HadCM_old_2PIC_monthly),
                        color='r', alpha=0.2, label='95% Confidence Interval')
axes[1, 5].set_xticks(months_scale)
axes[1, 5].set_xticklabels(month_names, rotation=45, ha="right")
axes[1, 5].set_title('SAT D47 values')
axes[1, 5].set_xlabel('Month')
axes[1, 5].set_ylabel('D47 value')
# axes[1, 5].legend()
axes[1, 5].grid(True)

# Plot the prior distribution for d18Oc
axes[2, 5].plot(months_scale, mu_prior_HadCM_old_2PIC_d18Oc_monthly, label='Prior d18Oc Mean', color='purple', marker='o')
axes[2, 5].fill_between(months_scale,
                        mu_prior_HadCM_old_2PIC_d18Oc_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_old_2PIC_monthly) * std_prior_HadCM_old_2PIC_d18Oc_monthly / np.sqrt(n_models_HadCM_old_2PIC_monthly),
                        mu_prior_HadCM_old_2PIC_d18Oc_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_old_2PIC_monthly) * std_prior_HadCM_old_2PIC_d18Oc_monthly / np.sqrt(n_models_HadCM_old_2PIC_monthly),
                        color='purple', alpha=0.2, label='95% Confidence Interval')
axes[2, 5].set_xticks(months_scale)
axes[2, 5].set_xticklabels(month_names, rotation=45, ha="right")
axes[2, 5].set_title('d18Oc values')
axes[2, 5].set_xlabel('Month')
axes[2, 5].set_ylabel('d18Oc value')
# axes[2, 5].legend()
axes[2, 5].grid(True)

# Plot the prior distribution for precipitation
axes[3, 5].plot(months_scale, mu_prior_HadCM_old_2PIC_precip_monthly, label='Prior Precipitation Mean', color='teal', marker='o')
axes[3, 5].fill_between(months_scale,
                        mu_prior_HadCM_old_2PIC_precip_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_old_2PIC_monthly) * std_prior_HadCM_old_2PIC_precip_monthly / np.sqrt(n_models_HadCM_old_2PIC_monthly),
                        mu_prior_HadCM_old_2PIC_precip_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_old_2PIC_monthly) * std_prior_HadCM_old_2PIC_precip_monthly / np.sqrt(n_models_HadCM_old_2PIC_monthly),
                        color='teal', alpha=0.2, label='95% Confidence Interval')
axes[3, 5].set_xticks(months_scale)
axes[3, 5].set_xticklabels(month_names, rotation=45, ha="right")
axes[3, 5].set_title('Precipitation values')
axes[3, 5].set_xlabel('Month')
axes[3, 5].set_ylabel('Precipitation (mm/day)')
# axes[3, 5].legend()
axes[3, 5].grid(True)

# Now for priors for old HadCM model with 4x preindustrial CO2
# Plot the prior distribution for SST
axes[0, 6].plot(months_scale, mu_prior_HadCM_old_4PIC_SST_D47_monthly, label='Prior SST Mean', color='b', marker='o')
axes[0, 6].fill_between(months_scale,
                        mu_prior_HadCM_old_4PIC_SST_D47_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_old_4PIC_monthly) * std_prior_HadCM_old_4PIC_SST_D47_monthly / np.sqrt(n_models_HadCM_old_4PIC_monthly),
                        mu_prior_HadCM_old_4PIC_SST_D47_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_old_4PIC_monthly) * std_prior_HadCM_old_4PIC_SST_D47_monthly / np.sqrt(n_models_HadCM_old_4PIC_monthly),
                        color='b', alpha=0.2, label='95% Confidence Interval')
axes[0, 6].set_xticks(months_scale)
axes[0, 6].set_xticklabels(month_names, rotation=45, ha="right")
axes[0, 6].set_title('HadCM (old)\n4x preindustrial pCO2\nSST D47 values')
axes[0, 6].set_xlabel('Month')
axes[0, 6].set_ylabel('D47 value')
# axes[0, 6].legend()
axes[0, 6].grid(True)

# Plot the prior distribution for SAT
axes[1, 6].plot(months_scale, mu_prior_HadCM_old_4PIC_SAT_D47_monthly, label='Prior SAT Mean', color='r', marker='o')
axes[1, 6].fill_between(months_scale,
                        mu_prior_HadCM_old_4PIC_SAT_D47_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_old_4PIC_monthly) * std_prior_HadCM_old_4PIC_SAT_D47_monthly / np.sqrt(n_models_HadCM_old_4PIC_monthly),
                        mu_prior_HadCM_old_4PIC_SAT_D47_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_old_4PIC_monthly) * std_prior_HadCM_old_4PIC_SAT_D47_monthly / np.sqrt(n_models_HadCM_old_4PIC_monthly),
                        color='r', alpha=0.2, label='95% Confidence Interval')
axes[1, 6].set_xticks(months_scale)
axes[1, 6].set_xticklabels(month_names, rotation=45, ha="right")
axes[1, 6].set_title('SAT D47 values')
axes[1, 6].set_xlabel('Month')
axes[1, 6].set_ylabel('D47 value')
# axes[1, 6].legend()
axes[1, 6].grid(True)

# Plot the prior distribution for d18Oc
axes[2, 6].plot(months_scale, mu_prior_HadCM_old_4PIC_d18Oc_monthly, label='Prior d18Oc Mean', color='purple', marker='o')
axes[2, 6].fill_between(months_scale,
                        mu_prior_HadCM_old_4PIC_d18Oc_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_old_4PIC_monthly) * std_prior_HadCM_old_4PIC_d18Oc_monthly / np.sqrt(n_models_HadCM_old_4PIC_monthly),
                        mu_prior_HadCM_old_4PIC_d18Oc_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_old_4PIC_monthly) * std_prior_HadCM_old_4PIC_d18Oc_monthly / np.sqrt(n_models_HadCM_old_4PIC_monthly),
                        color='purple', alpha=0.2, label='95% Confidence Interval')
axes[2, 6].set_xticks(months_scale)
axes[2, 6].set_xticklabels(month_names, rotation=45, ha="right")
axes[2, 6].set_title('d18Oc values')
axes[2, 6].set_xlabel('Month')
axes[2, 6].set_ylabel('d18Oc value')
# axes[2, 6].legend()
axes[2, 6].grid(True)

# Plot the prior distribution for precipitation
axes[3, 6].plot(months_scale, mu_prior_HadCM_old_4PIC_precip_monthly, label='Prior Precipitation Mean', color='teal', marker='o')
axes[3, 6].fill_between(months_scale,
                        mu_prior_HadCM_old_4PIC_precip_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_old_4PIC_monthly) * std_prior_HadCM_old_4PIC_precip_monthly / np.sqrt(n_models_HadCM_old_4PIC_monthly),
                        mu_prior_HadCM_old_4PIC_precip_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_old_4PIC_monthly) * std_prior_HadCM_old_4PIC_precip_monthly / np.sqrt(n_models_HadCM_old_4PIC_monthly),
                        color='teal', alpha=0.2, label='95% Confidence Interval')
axes[3, 6].set_xticks(months_scale)
axes[3, 6].set_xticklabels(month_names, rotation=45, ha="right")
axes[3, 6].set_title('Precipitation values')
axes[3, 6].set_xlabel('Month')
axes[3, 6].set_ylabel('Precipitation (mm/day)')
# axes[3, 6].legend()
axes[3, 6].grid(True)

# Update the layout and show the plot
plt.tight_layout()
plt.show()
No description has been provided for this image

Calculate the monthly covariance matrix for D47 values of SST and SAT, d18Oc and precipitation¶

First for CESM model with 4x pre-industrial CO2¶

In [39]:
# Define column names for SAT, SST, d18Oc, and precipitation
SAT_D47_CESM_4PIC_columns_monthly = [f"{month}_SAT_D47" for month in months]
SST_D47_CESM_4PIC_columns_monthly = [f"{month}_SST_D47" for month in months]
d18Oc_CESM_4PIC_columns_monthly = [f"{month}_d18Oc" for month in months]
precip_CESM_4PIC_columns_monthly = [f"{month}_precip" for month in months]

# Extract the relevant columns for SAT, SST D47, d18Oc, and precipitation
SAT_D47_CESM_4PIC_columns_monthly = [f"{month}_SAT_D47" for month in months]
SST_D47_CESM_4PIC_columns_monthly = [f"{month}_SST_D47" for month in months]
d18Oc_CESM_4PIC_columns_monthly = [f"{month}_d18Oc" for month in months]
precip_CESM_4PIC_columns_monthly = [f"{month}_precip" for month in months]

# Combine the relevant columns into a single dataframe
combined_data_CESM_4PIC_monthly = Lutetian_CESM_4PIC_model[SAT_D47_CESM_4PIC_columns_monthly + SST_D47_CESM_4PIC_columns_monthly + d18Oc_CESM_4PIC_columns_monthly + precip_CESM_4PIC_columns_monthly]

# Calculate the covariance matrix for the combined data
cov_combined_CESM_4PIC_monthly = np.cov(combined_data_CESM_4PIC_monthly.dropna(), rowvar=False)

# Plot the heatmap of the raw combined covariance matrix
plt.figure(figsize=(12, 10))
sns.heatmap(
    cov_combined_CESM_4PIC_monthly,  # Use the raw covariance matrix
    annot=False,
    fmt=".2f",
    cmap="coolwarm",
    center=0,
    xticklabels=SAT_D47_CESM_4PIC_columns_monthly + SST_D47_CESM_4PIC_columns_monthly + d18Oc_CESM_4PIC_columns_monthly + precip_CESM_4PIC_columns_monthly,
    yticklabels=SAT_D47_CESM_4PIC_columns_monthly + SST_D47_CESM_4PIC_columns_monthly + d18Oc_CESM_4PIC_columns_monthly + precip_CESM_4PIC_columns_monthly
)

# Add titles to the axes per parameter
plt.axvline(x=len(SAT_D47_CESM_4PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_CESM_4PIC_columns_monthly) + len(SST_D47_CESM_4PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_CESM_4PIC_columns_monthly) + len(SST_D47_CESM_4PIC_columns_monthly) + len(d18Oc_CESM_4PIC_columns_monthly), color='black', linestyle='--', linewidth=1)

plt.axhline(y=len(SAT_D47_CESM_4PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_CESM_4PIC_columns_monthly) + len(SST_D47_CESM_4PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_CESM_4PIC_columns_monthly) + len(SST_D47_CESM_4PIC_columns_monthly) + len(d18Oc_CESM_4PIC_columns_monthly), color='black', linestyle='--', linewidth=1)

# Add parameter labels
plt.text(len(SAT_D47_CESM_4PIC_columns_monthly) / 2, -2, 'D47 value from SAT', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_CESM_4PIC_columns_monthly) + len(SST_D47_CESM_4PIC_columns_monthly) / 2, -2, 'D47 value from SST', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_CESM_4PIC_columns_monthly) + len(SST_D47_CESM_4PIC_columns_monthly) + len(d18Oc_CESM_4PIC_columns_monthly) / 2, -2, 'd18Oc', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_CESM_4PIC_columns_monthly) + len(SST_D47_CESM_4PIC_columns_monthly) + len(d18Oc_CESM_4PIC_columns_monthly) + len(precip_CESM_4PIC_columns_monthly) / 2, -2, 'Precipitation', ha='center', va='center', fontsize=10)

plt.text(-2, len(SAT_D47_CESM_4PIC_columns_monthly) / 2, 'D47 value from SAT', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-2, len(SAT_D47_CESM_4PIC_columns_monthly) + len(SST_D47_CESM_4PIC_columns_monthly) / 2, 'D47 value from SST', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-2, len(SAT_D47_CESM_4PIC_columns_monthly) + len(SST_D47_CESM_4PIC_columns_monthly) + len(d18Oc_CESM_4PIC_columns_monthly) / 2, 'd18Oc', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-2, len(SAT_D47_CESM_4PIC_columns_monthly) + len(SST_D47_CESM_4PIC_columns_monthly) + len(d18Oc_CESM_4PIC_columns_monthly) + len(precip_CESM_4PIC_columns_monthly) / 2, 'Precipitation', ha='center', va='center', rotation=90, fontsize=10)

plt.title("Raw Combined Covariance Matrix (CESM 4x preindustrial pCO2)")
plt.show()
No description has been provided for this image

Then for CESM model with 2x pre-industrial CO2¶

In [40]:
# Define column names for SAT, SST, d18Oc, and precipitation
SAT_D47_CESM_2PIC_columns_monthly = [f"{month}_SAT_D47" for month in months]
SST_D47_CESM_2PIC_columns_monthly = [f"{month}_SST_D47" for month in months]
d18Oc_CESM_2PIC_columns_monthly = [f"{month}_d18Oc" for month in months]
precip_CESM_2PIC_columns_monthly = [f"{month}_precip" for month in months]

# Extract the relevant columns for SAT, SST D47, d18Oc, and precipitation
SAT_D47_CESM_2PIC_columns_monthly = [f"{month}_SAT_D47" for month in months]
SST_D47_CESM_2PIC_columns_monthly = [f"{month}_SST_D47" for month in months]
d18Oc_CESM_2PIC_columns_monthly = [f"{month}_d18Oc" for month in months]
precip_CESM_2PIC_columns_monthly = [f"{month}_precip" for month in months]

# Combine the relevant columns into a single dataframe
combined_data_CESM_2PIC_monthly = Lutetian_CESM_2PIC_model[SAT_D47_CESM_2PIC_columns_monthly + SST_D47_CESM_2PIC_columns_monthly + d18Oc_CESM_2PIC_columns_monthly + precip_CESM_2PIC_columns_monthly]

# Calculate the covariance matrix for the combined data
cov_combined_CESM_2PIC_monthly = np.cov(combined_data_CESM_2PIC_monthly.dropna(), rowvar=False)

# Plot the heatmap of the raw combined covariance matrix
plt.figure(figsize=(12, 10))
sns.heatmap(
    cov_combined_CESM_2PIC_monthly,  # Use the raw covariance matrix
    annot=False,
    fmt=".2f",
    cmap="coolwarm",
    center=0,
    xticklabels=SAT_D47_CESM_2PIC_columns_monthly + SST_D47_CESM_2PIC_columns_monthly + d18Oc_CESM_2PIC_columns_monthly + precip_CESM_2PIC_columns_monthly,
    yticklabels=SAT_D47_CESM_2PIC_columns_monthly + SST_D47_CESM_2PIC_columns_monthly + d18Oc_CESM_2PIC_columns_monthly + precip_CESM_2PIC_columns_monthly
)

# Add titles to the axes per parameter
plt.axvline(x=len(SAT_D47_CESM_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly) + len(d18Oc_CESM_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)

plt.axhline(y=len(SAT_D47_CESM_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly) + len(d18Oc_CESM_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)

# Add parameter labels
plt.text(len(SAT_D47_CESM_2PIC_columns_monthly) / 2, -2, 'D47 value from SAT', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly) / 2, -2, 'D47 value from SST', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly) + len(d18Oc_CESM_2PIC_columns_monthly) / 2, -2, 'd18Oc', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly) + len(d18Oc_CESM_2PIC_columns_monthly) + len(precip_CESM_2PIC_columns_monthly) / 2, -2, 'Precipitation', ha='center', va='center', fontsize=10)

plt.text(-2, len(SAT_D47_CESM_2PIC_columns_monthly) / 2, 'D47 value from SAT', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-2, len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly) / 2, 'D47 value from SST', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-2, len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly) + len(d18Oc_CESM_2PIC_columns_monthly) / 2, 'd18Oc', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-2, len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly) + len(d18Oc_CESM_2PIC_columns_monthly) + len(precip_CESM_2PIC_columns_monthly) / 2, 'Precipitation', ha='center', va='center', rotation=90, fontsize=10)

plt.title("Raw Combined Covariance Matrix (CESM 2x preindustrial pCO2)")
plt.show()
No description has been provided for this image

Then for HadCM model with 1x pre-industrial CO2¶

In [41]:
# Define column names for SAT, SST, d18Oc, and precipitation
SAT_D47_HadCM_new_1PIC_columns_monthly = [f"{month}_SAT_D47" for month in months]
SST_D47_HadCM_new_1PIC_columns_monthly = [f"{month}_SST_D47" for month in months]
d18Oc_HadCM_new_1PIC_columns_monthly = [f"{month}_d18Oc" for month in months]
precip_HadCM_new_1PIC_columns_monthly = [f"{month}_precip" for month in months]

# Extract the relevant columns for SAT, SST D47, d18Oc, and precipitation
SAT_D47_HadCM_new_1PIC_columns_monthly = [f"{month}_SAT_D47" for month in months]
SST_D47_HadCM_new_1PIC_columns_monthly = [f"{month}_SST_D47" for month in months]
d18Oc_HadCM_new_1PIC_columns_monthly = [f"{month}_d18Oc" for month in months]
precip_HadCM_new_1PIC_columns_monthly = [f"{month}_precip" for month in months]

# Combine the relevant columns into a single dataframe
combined_data_HadCM_new_1PIC_monthly = Lutetian_HadCM_new_1PIC_model[SAT_D47_HadCM_new_1PIC_columns_monthly + SST_D47_HadCM_new_1PIC_columns_monthly + d18Oc_HadCM_new_1PIC_columns_monthly + precip_HadCM_new_1PIC_columns_monthly]

# Calculate the covariance matrix for the combined data
cov_combined_HadCM_new_1PIC_monthly = np.cov(combined_data_HadCM_new_1PIC_monthly.dropna(), rowvar=False)

# Plot the heatmap of the raw combined covariance matrix
plt.figure(figsize=(12, 10))
sns.heatmap(
    cov_combined_HadCM_new_1PIC_monthly,  # Use the raw covariance matrix
    annot=False,
    fmt=".2f",
    cmap="coolwarm",
    center=0,
    xticklabels=SAT_D47_HadCM_new_1PIC_columns_monthly + SST_D47_HadCM_new_1PIC_columns_monthly + d18Oc_HadCM_new_1PIC_columns_monthly + precip_HadCM_new_1PIC_columns_monthly,
    yticklabels=SAT_D47_HadCM_new_1PIC_columns_monthly + SST_D47_HadCM_new_1PIC_columns_monthly + d18Oc_HadCM_new_1PIC_columns_monthly + precip_HadCM_new_1PIC_columns_monthly
)

# Add titles to the axes per parameter
plt.axvline(x=len(SAT_D47_HadCM_new_1PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_HadCM_new_1PIC_columns_monthly) + len(SST_D47_HadCM_new_1PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_HadCM_new_1PIC_columns_monthly) + len(SST_D47_HadCM_new_1PIC_columns_monthly) + len(d18Oc_HadCM_new_1PIC_columns_monthly), color='black', linestyle='--', linewidth=1)

plt.axhline(y=len(SAT_D47_HadCM_new_1PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_HadCM_new_1PIC_columns_monthly) + len(SST_D47_HadCM_new_1PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_HadCM_new_1PIC_columns_monthly) + len(SST_D47_HadCM_new_1PIC_columns_monthly) + len(d18Oc_HadCM_new_1PIC_columns_monthly), color='black', linestyle='--', linewidth=1)

# Add parameter labels
plt.text(len(SAT_D47_HadCM_new_1PIC_columns_monthly) / 2, -2, 'D47 value from SAT', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_new_1PIC_columns_monthly) + len(SST_D47_HadCM_new_1PIC_columns_monthly) / 2, -2, 'D47 value from SST', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_new_1PIC_columns_monthly) + len(SST_D47_HadCM_new_1PIC_columns_monthly) + len(d18Oc_HadCM_new_1PIC_columns_monthly) / 2, -2, 'd18Oc', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_new_1PIC_columns_monthly) + len(SST_D47_HadCM_new_1PIC_columns_monthly) + len(d18Oc_HadCM_new_1PIC_columns_monthly) + len(precip_HadCM_new_1PIC_columns_monthly) / 2, -2, 'Precipitation', ha='center', va='center', fontsize=10)

plt.text(-2, len(SAT_D47_HadCM_new_1PIC_columns_monthly) / 2, 'D47 value from SAT', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-2, len(SAT_D47_HadCM_new_1PIC_columns_monthly) + len(SST_D47_HadCM_new_1PIC_columns_monthly) / 2, 'D47 value from SST', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-2, len(SAT_D47_HadCM_new_1PIC_columns_monthly) + len(SST_D47_HadCM_new_1PIC_columns_monthly) + len(d18Oc_HadCM_new_1PIC_columns_monthly) / 2, 'd18Oc', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-2, len(SAT_D47_HadCM_new_1PIC_columns_monthly) + len(SST_D47_HadCM_new_1PIC_columns_monthly) + len(d18Oc_HadCM_new_1PIC_columns_monthly) + len(precip_HadCM_new_1PIC_columns_monthly) / 2, 'Precipitation', ha='center', va='center', rotation=90, fontsize=10)

plt.title("Raw Combined Covariance Matrix (CESM 2x preindustrial pCO2)")
plt.show()
No description has been provided for this image

Then for HadCM model with 2x pre-industrial CO2¶

In [42]:
# Define column names for SAT, SST, d18Oc, and precipitation
SAT_D47_HadCM_new_2PIC_columns_monthly = [f"{month}_SAT_D47" for month in months]
SST_D47_HadCM_new_2PIC_columns_monthly = [f"{month}_SST_D47" for month in months]
d18Oc_HadCM_new_2PIC_columns_monthly = [f"{month}_d18Oc" for month in months]
precip_HadCM_new_2PIC_columns_monthly = [f"{month}_precip" for month in months]

# Extract the relevant columns for SAT, SST D47, d18Oc, and precipitation
SAT_D47_HadCM_new_2PIC_columns_monthly = [f"{month}_SAT_D47" for month in months]
SST_D47_HadCM_new_2PIC_columns_monthly = [f"{month}_SST_D47" for month in months]
d18Oc_HadCM_new_2PIC_columns_monthly = [f"{month}_d18Oc" for month in months]
precip_HadCM_new_2PIC_columns_monthly = [f"{month}_precip" for month in months]

# Combine the relevant columns into a single dataframe
combined_data_HadCM_new_2PIC_monthly = Lutetian_HadCM_new_2PIC_model[SAT_D47_HadCM_new_2PIC_columns_monthly + SST_D47_HadCM_new_2PIC_columns_monthly + d18Oc_HadCM_new_2PIC_columns_monthly + precip_HadCM_new_2PIC_columns_monthly]

# Calculate the covariance matrix for the combined data
cov_combined_HadCM_new_2PIC_monthly = np.cov(combined_data_HadCM_new_2PIC_monthly.dropna(), rowvar=False)

# Plot the heatmap of the raw combined covariance matrix
plt.figure(figsize=(12, 10))
sns.heatmap(
    cov_combined_HadCM_new_2PIC_monthly,  # Use the raw covariance matrix
    annot=False,
    fmt=".2f",
    cmap="coolwarm",
    center=0,
    xticklabels=SAT_D47_HadCM_new_2PIC_columns_monthly + SST_D47_HadCM_new_2PIC_columns_monthly + d18Oc_HadCM_new_2PIC_columns_monthly + precip_HadCM_new_2PIC_columns_monthly,
    yticklabels=SAT_D47_HadCM_new_2PIC_columns_monthly + SST_D47_HadCM_new_2PIC_columns_monthly + d18Oc_HadCM_new_2PIC_columns_monthly + precip_HadCM_new_2PIC_columns_monthly
)

# Add titles to the axes per parameter
plt.axvline(x=len(SAT_D47_HadCM_new_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_HadCM_new_2PIC_columns_monthly) + len(SST_D47_HadCM_new_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_HadCM_new_2PIC_columns_monthly) + len(SST_D47_HadCM_new_2PIC_columns_monthly) + len(d18Oc_HadCM_new_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)

plt.axhline(y=len(SAT_D47_HadCM_new_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_HadCM_new_2PIC_columns_monthly) + len(SST_D47_HadCM_new_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_HadCM_new_2PIC_columns_monthly) + len(SST_D47_HadCM_new_2PIC_columns_monthly) + len(d18Oc_HadCM_new_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)

# Add parameter labels
plt.text(len(SAT_D47_HadCM_new_2PIC_columns_monthly) / 2, -2, 'D47 value from SAT', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_new_2PIC_columns_monthly) + len(SST_D47_HadCM_new_2PIC_columns_monthly) / 2, -2, 'D47 value from SST', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_new_2PIC_columns_monthly) + len(SST_D47_HadCM_new_2PIC_columns_monthly) + len(d18Oc_HadCM_new_2PIC_columns_monthly) / 2, -2, 'd18Oc', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_new_2PIC_columns_monthly) + len(SST_D47_HadCM_new_2PIC_columns_monthly) + len(d18Oc_HadCM_new_2PIC_columns_monthly) + len(precip_HadCM_new_2PIC_columns_monthly) / 2, -2, 'Precipitation', ha='center', va='center', fontsize=10)

plt.text(-2, len(SAT_D47_HadCM_new_2PIC_columns_monthly) / 2, 'D47 value from SAT', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-2, len(SAT_D47_HadCM_new_2PIC_columns_monthly) + len(SST_D47_HadCM_new_2PIC_columns_monthly) / 2, 'D47 value from SST', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-2, len(SAT_D47_HadCM_new_2PIC_columns_monthly) + len(SST_D47_HadCM_new_2PIC_columns_monthly) + len(d18Oc_HadCM_new_2PIC_columns_monthly) / 2, 'd18Oc', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-2, len(SAT_D47_HadCM_new_2PIC_columns_monthly) + len(SST_D47_HadCM_new_2PIC_columns_monthly) + len(d18Oc_HadCM_new_2PIC_columns_monthly) + len(precip_HadCM_new_2PIC_columns_monthly) / 2, 'Precipitation', ha='center', va='center', rotation=90, fontsize=10)

plt.title("Raw Combined Covariance Matrix (CESM 2x preindustrial pCO2)")
plt.show()
No description has been provided for this image

Then for HadCM model with 1056 ppm CO2¶

In [43]:
# Define column names for SAT, SST, d18Oc, and precipitation
SAT_D47_HadCM_new_1056ppm_columns_monthly = [f"{month}_SAT_D47" for month in months]
SST_D47_HadCM_new_1056ppm_columns_monthly = [f"{month}_SST_D47" for month in months]
d18Oc_HadCM_new_1056ppm_columns_monthly = [f"{month}_d18Oc" for month in months]
precip_HadCM_new_1056ppm_columns_monthly = [f"{month}_precip" for month in months]

# Extract the relevant columns for SAT, SST D47, d18Oc, and precipitation
SAT_D47_HadCM_new_1056ppm_columns_monthly = [f"{month}_SAT_D47" for month in months]
SST_D47_HadCM_new_1056ppm_columns_monthly = [f"{month}_SST_D47" for month in months]
d18Oc_HadCM_new_1056ppm_columns_monthly = [f"{month}_d18Oc" for month in months]
precip_HadCM_new_1056ppm_columns_monthly = [f"{month}_precip" for month in months]

# Combine the relevant columns into a single dataframe
combined_data_HadCM_new_1056ppm_monthly = Lutetian_HadCM_new_1056ppm_model[SAT_D47_HadCM_new_1056ppm_columns_monthly + SST_D47_HadCM_new_1056ppm_columns_monthly + d18Oc_HadCM_new_1056ppm_columns_monthly + precip_HadCM_new_1056ppm_columns_monthly]

# Calculate the covariance matrix for the combined data
cov_combined_HadCM_new_1056ppm_monthly = np.cov(combined_data_HadCM_new_1056ppm_monthly.dropna(), rowvar=False)

# Plot the heatmap of the raw combined covariance matrix
plt.figure(figsize=(12, 10))
sns.heatmap(
    cov_combined_HadCM_new_1056ppm_monthly,  # Use the raw covariance matrix
    annot=False,
    fmt=".2f",
    cmap="coolwarm",
    center=0,
    xticklabels=SAT_D47_HadCM_new_1056ppm_columns_monthly + SST_D47_HadCM_new_1056ppm_columns_monthly + d18Oc_HadCM_new_1056ppm_columns_monthly + precip_HadCM_new_1056ppm_columns_monthly,
    yticklabels=SAT_D47_HadCM_new_1056ppm_columns_monthly + SST_D47_HadCM_new_1056ppm_columns_monthly + d18Oc_HadCM_new_1056ppm_columns_monthly + precip_HadCM_new_1056ppm_columns_monthly
)

# Add titles to the axes per parameter
plt.axvline(x=len(SAT_D47_HadCM_new_1056ppm_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_HadCM_new_1056ppm_columns_monthly) + len(SST_D47_HadCM_new_1056ppm_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_HadCM_new_1056ppm_columns_monthly) + len(SST_D47_HadCM_new_1056ppm_columns_monthly) + len(d18Oc_HadCM_new_1056ppm_columns_monthly), color='black', linestyle='--', linewidth=1)

plt.axhline(y=len(SAT_D47_HadCM_new_1056ppm_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_HadCM_new_1056ppm_columns_monthly) + len(SST_D47_HadCM_new_1056ppm_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_HadCM_new_1056ppm_columns_monthly) + len(SST_D47_HadCM_new_1056ppm_columns_monthly) + len(d18Oc_HadCM_new_1056ppm_columns_monthly), color='black', linestyle='--', linewidth=1)

# Add parameter labels
plt.text(len(SAT_D47_HadCM_new_1056ppm_columns_monthly) / 2, -2, 'D47 value from SAT', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_new_1056ppm_columns_monthly) + len(SST_D47_HadCM_new_1056ppm_columns_monthly) / 2, -2, 'D47 value from SST', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_new_1056ppm_columns_monthly) + len(SST_D47_HadCM_new_1056ppm_columns_monthly) + len(d18Oc_HadCM_new_1056ppm_columns_monthly) / 2, -2, 'd18Oc', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_new_1056ppm_columns_monthly) + len(SST_D47_HadCM_new_1056ppm_columns_monthly) + len(d18Oc_HadCM_new_1056ppm_columns_monthly) + len(precip_HadCM_new_1056ppm_columns_monthly) / 2, -2, 'Precipitation', ha='center', va='center', fontsize=10)

plt.text(-2, len(SAT_D47_HadCM_new_1056ppm_columns_monthly) / 2, 'D47 value from SAT', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-2, len(SAT_D47_HadCM_new_1056ppm_columns_monthly) + len(SST_D47_HadCM_new_1056ppm_columns_monthly) / 2, 'D47 value from SST', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-2, len(SAT_D47_HadCM_new_1056ppm_columns_monthly) + len(SST_D47_HadCM_new_1056ppm_columns_monthly) + len(d18Oc_HadCM_new_1056ppm_columns_monthly) / 2, 'd18Oc', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-2, len(SAT_D47_HadCM_new_1056ppm_columns_monthly) + len(SST_D47_HadCM_new_1056ppm_columns_monthly) + len(d18Oc_HadCM_new_1056ppm_columns_monthly) + len(precip_HadCM_new_1056ppm_columns_monthly) / 2, 'Precipitation', ha='center', va='center', rotation=90, fontsize=10)

plt.title("Raw Combined Covariance Matrix (CESM 2x preindustrial pCO2)")
plt.show()
No description has been provided for this image

Then for old HadCM model with 2x pre-industrial CO2¶

In [44]:
# Define column names for SAT, SST, d18Oc, and precipitation
SAT_D47_HadCM_old_2PIC_columns_monthly = [f"{month}_SAT_D47" for month in months]
SST_D47_HadCM_old_2PIC_columns_monthly = [f"{month}_SST_D47" for month in months]
d18Oc_HadCM_old_2PIC_columns_monthly = [f"{month}_d18Oc" for month in months]
precip_HadCM_old_2PIC_columns_monthly = [f"{month}_precip" for month in months]

# Extract the relevant columns for SAT, SST D47, d18Oc, and precipitation
SAT_D47_HadCM_old_2PIC_columns_monthly = [f"{month}_SAT_D47" for month in months]
SST_D47_HadCM_old_2PIC_columns_monthly = [f"{month}_SST_D47" for month in months]
d18Oc_HadCM_old_2PIC_columns_monthly = [f"{month}_d18Oc" for month in months]
precip_HadCM_old_2PIC_columns_monthly = [f"{month}_precip" for month in months]

# Combine the relevant columns into a single dataframe
combined_data_HadCM_old_2PIC_monthly = Lutetian_HadCM_old_2PIC_model[SAT_D47_HadCM_old_2PIC_columns_monthly + SST_D47_HadCM_old_2PIC_columns_monthly + d18Oc_HadCM_old_2PIC_columns_monthly + precip_HadCM_old_2PIC_columns_monthly]

# Calculate the covariance matrix for the combined data
cov_combined_HadCM_old_2PIC_monthly = np.cov(combined_data_HadCM_old_2PIC_monthly.dropna(), rowvar=False)

# Plot the heatmap of the raw combined covariance matrix
plt.figure(figsize=(12, 10))
sns.heatmap(
    cov_combined_HadCM_old_2PIC_monthly,  # Use the raw covariance matrix
    annot=False,
    fmt=".2f",
    cmap="coolwarm",
    center=0,
    xticklabels=SAT_D47_HadCM_old_2PIC_columns_monthly + SST_D47_HadCM_old_2PIC_columns_monthly + d18Oc_HadCM_old_2PIC_columns_monthly + precip_HadCM_old_2PIC_columns_monthly,
    yticklabels=SAT_D47_HadCM_old_2PIC_columns_monthly + SST_D47_HadCM_old_2PIC_columns_monthly + d18Oc_HadCM_old_2PIC_columns_monthly + precip_HadCM_old_2PIC_columns_monthly
)

# Add titles to the axes per parameter
plt.axvline(x=len(SAT_D47_HadCM_old_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly) + len(d18Oc_HadCM_old_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)

plt.axhline(y=len(SAT_D47_HadCM_old_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly) + len(d18Oc_HadCM_old_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)

# Add parameter labels
plt.text(len(SAT_D47_HadCM_old_2PIC_columns_monthly) / 2, -2, 'D47 value from SAT', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly) / 2, -2, 'D47 value from SST', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly) + len(d18Oc_HadCM_old_2PIC_columns_monthly) / 2, -2, 'd18Oc', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly) + len(d18Oc_HadCM_old_2PIC_columns_monthly) + len(precip_HadCM_old_2PIC_columns_monthly) / 2, -2, 'Precipitation', ha='center', va='center', fontsize=10)

plt.text(-2, len(SAT_D47_HadCM_old_2PIC_columns_monthly) / 2, 'D47 value from SAT', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-2, len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly) / 2, 'D47 value from SST', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-2, len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly) + len(d18Oc_HadCM_old_2PIC_columns_monthly) / 2, 'd18Oc', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-2, len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly) + len(d18Oc_HadCM_old_2PIC_columns_monthly) + len(precip_HadCM_old_2PIC_columns_monthly) / 2, 'Precipitation', ha='center', va='center', rotation=90, fontsize=10)

plt.title("Raw Combined Covariance Matrix (CESM 2x preindustrial pCO2)")
plt.show()
No description has been provided for this image

Then for old HadCM model with 4x pre-industrial CO2¶

In [45]:
# Define column names for SAT, SST, d18Oc, and precipitation
SAT_D47_HadCM_old_4PIC_columns_monthly = [f"{month}_SAT_D47" for month in months]
SST_D47_HadCM_old_4PIC_columns_monthly = [f"{month}_SST_D47" for month in months]
d18Oc_HadCM_old_4PIC_columns_monthly = [f"{month}_d18Oc" for month in months]
precip_HadCM_old_4PIC_columns_monthly = [f"{month}_precip" for month in months]

# Extract the relevant columns for SAT, SST D47, d18Oc, and precipitation
SAT_D47_HadCM_old_4PIC_columns_monthly = [f"{month}_SAT_D47" for month in months]
SST_D47_HadCM_old_4PIC_columns_monthly = [f"{month}_SST_D47" for month in months]
d18Oc_HadCM_old_4PIC_columns_monthly = [f"{month}_d18Oc" for month in months]
precip_HadCM_old_4PIC_columns_monthly = [f"{month}_precip" for month in months]

# Combine the relevant columns into a single dataframe
combined_data_HadCM_old_4PIC_monthly = Lutetian_HadCM_old_4PIC_model[SAT_D47_HadCM_old_4PIC_columns_monthly + SST_D47_HadCM_old_4PIC_columns_monthly + d18Oc_HadCM_old_4PIC_columns_monthly + precip_HadCM_old_4PIC_columns_monthly]

# Calculate the covariance matrix for the combined data
cov_combined_HadCM_old_4PIC_monthly = np.cov(combined_data_HadCM_old_4PIC_monthly.dropna(), rowvar=False)

# Plot the heatmap of the raw combined covariance matrix
plt.figure(figsize=(12, 10))
sns.heatmap(
    cov_combined_HadCM_old_4PIC_monthly,  # Use the raw covariance matrix
    annot=False,
    fmt=".2f",
    cmap="coolwarm",
    center=0,
    xticklabels=SAT_D47_HadCM_old_4PIC_columns_monthly + SST_D47_HadCM_old_4PIC_columns_monthly + d18Oc_HadCM_old_4PIC_columns_monthly + precip_HadCM_old_4PIC_columns_monthly,
    yticklabels=SAT_D47_HadCM_old_4PIC_columns_monthly + SST_D47_HadCM_old_4PIC_columns_monthly + d18Oc_HadCM_old_4PIC_columns_monthly + precip_HadCM_old_4PIC_columns_monthly
)

# Add titles to the axes per parameter
plt.axvline(x=len(SAT_D47_HadCM_old_4PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_HadCM_old_4PIC_columns_monthly) + len(SST_D47_HadCM_old_4PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_HadCM_old_4PIC_columns_monthly) + len(SST_D47_HadCM_old_4PIC_columns_monthly) + len(d18Oc_HadCM_old_4PIC_columns_monthly), color='black', linestyle='--', linewidth=1)

plt.axhline(y=len(SAT_D47_HadCM_old_4PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_HadCM_old_4PIC_columns_monthly) + len(SST_D47_HadCM_old_4PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_HadCM_old_4PIC_columns_monthly) + len(SST_D47_HadCM_old_4PIC_columns_monthly) + len(d18Oc_HadCM_old_4PIC_columns_monthly), color='black', linestyle='--', linewidth=1)

# Add parameter labels
plt.text(len(SAT_D47_HadCM_old_4PIC_columns_monthly) / 2, -2, 'D47 value from SAT', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_old_4PIC_columns_monthly) + len(SST_D47_HadCM_old_4PIC_columns_monthly) / 2, -2, 'D47 value from SST', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_old_4PIC_columns_monthly) + len(SST_D47_HadCM_old_4PIC_columns_monthly) + len(d18Oc_HadCM_old_4PIC_columns_monthly) / 2, -2, 'd18Oc', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_old_4PIC_columns_monthly) + len(SST_D47_HadCM_old_4PIC_columns_monthly) + len(d18Oc_HadCM_old_4PIC_columns_monthly) + len(precip_HadCM_old_4PIC_columns_monthly) / 2, -2, 'Precipitation', ha='center', va='center', fontsize=10)

plt.text(-2, len(SAT_D47_HadCM_old_4PIC_columns_monthly) / 2, 'D47 value from SAT', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-2, len(SAT_D47_HadCM_old_4PIC_columns_monthly) + len(SST_D47_HadCM_old_4PIC_columns_monthly) / 2, 'D47 value from SST', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-2, len(SAT_D47_HadCM_old_4PIC_columns_monthly) + len(SST_D47_HadCM_old_4PIC_columns_monthly) + len(d18Oc_HadCM_old_4PIC_columns_monthly) / 2, 'd18Oc', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-2, len(SAT_D47_HadCM_old_4PIC_columns_monthly) + len(SST_D47_HadCM_old_4PIC_columns_monthly) + len(d18Oc_HadCM_old_4PIC_columns_monthly) + len(precip_HadCM_old_4PIC_columns_monthly) / 2, 'Precipitation', ha='center', va='center', rotation=90, fontsize=10)

plt.title("Raw Combined Covariance Matrix (CESM 2x preindustrial pCO2)")
plt.show()
No description has been provided for this image

Plot normalized monthly covariance matrix between D47 values of SST and SAT, d18Oc and precipitation¶

Create function for normalizing matrices¶

In [46]:
# Normalize each submatrix independently for better visualization
def normalize_matrix(matrix):
    min_val = np.min(matrix)
    max_val = np.max(matrix)
    return (matrix - min_val) / (max_val - min_val)

First for CESM with 4x preindustrial pCO2¶

In [47]:
# Extract the relevant columns for SAT, SST D47, d18Oc, and precipitation
SAT_D47_CESM_4PIC_columns_monthly = [f"{month}_SAT_D47" for month in months]
SST_D47_CESM_4PIC_columns_monthly = [f"{month}_SST_D47" for month in months]
d18Oc_CESM_4PIC_columns_monthly = [f"{month}_d18Oc" for month in months]
precip_CESM_4PIC_columns_monthly = [f"{month}_precip" for month in months]

# Combine the relevant columns into a single dataframe
combined_data_CESM_4PIC_monthly = Lutetian_CESM_4PIC_model[SAT_D47_CESM_4PIC_columns_monthly + SST_D47_CESM_4PIC_columns_monthly + d18Oc_CESM_4PIC_columns_monthly + precip_CESM_4PIC_columns_monthly]

# Calculate the covariance matrix for the combined data
cov_combined_CESM_4PIC_monthly = np.cov(combined_data_CESM_4PIC_monthly.dropna(), rowvar=False)

# Extract the covariance matrices for SAT D47, SST D47, d18Oc, and precipitation
cov_CESM_4PIC_SAT_D47_monthly = cov_combined_CESM_4PIC_monthly[:len(months), :len(months)]
cov_CESM_4PIC_SST_D47_monthly = cov_combined_CESM_4PIC_monthly[len(months):2*len(months), len(months):2*len(months)]
cov_CESM_4PIC_d18Oc_monthly = cov_combined_CESM_4PIC_monthly[2*len(months):3*len(months), 2*len(months):3*len(months)]
cov_CESM_4PIC_precip_monthly = cov_combined_CESM_4PIC_monthly[3*len(months):, 3*len(months):]

# Extract the cross-covariance matrices
cross_cov_CESM_4PIC_SAT_SST_D47_monthly = cov_combined_CESM_4PIC_monthly[:len(months), len(months):2*len(months)]
cross_cov_CESM_4PIC_SAT_d18Oc_monthly = cov_combined_CESM_4PIC_monthly[:len(months), 2*len(months):3*len(months)]
cross_cov_CESM_4PIC_SAT_precip_monthly = cov_combined_CESM_4PIC_monthly[:len(months), 3*len(months):]
cross_cov_CESM_4PIC_SST_d18Oc_monthly = cov_combined_CESM_4PIC_monthly[len(months):2*len(months), 2*len(months):3*len(months)]
cross_cov_CESM_4PIC_SST_precip_monthly = cov_combined_CESM_4PIC_monthly[len(months):2*len(months), 3*len(months):]
cross_cov_CESM_4PIC_d18Oc_precip_monthly = cov_combined_CESM_4PIC_monthly[2*len(months):3*len(months), 3*len(months):]

# Normalize each submatrix
normalized_cov_CESM_4PIC_SAT_D47_monthly = normalize_matrix(cov_CESM_4PIC_SAT_D47_monthly)
normalized_cov_CESM_4PIC_SST_D47_monthly = normalize_matrix(cov_CESM_4PIC_SST_D47_monthly)
normalized_cov_CESM_4PIC_d18Oc_monthly = normalize_matrix(cov_CESM_4PIC_d18Oc_monthly)
normalized_cov_CESM_4PIC_precip_monthly = normalize_matrix(cov_CESM_4PIC_precip_monthly)

# Normalize each cross-covariance matrix
normalized_cross_cov_CESM_4PIC_SAT_SST_D47_monthly = normalize_matrix(cross_cov_CESM_4PIC_SAT_SST_D47_monthly)
normalized_cross_cov_CESM_4PIC_SAT_d18Oc_monthly = normalize_matrix(cross_cov_CESM_4PIC_SAT_d18Oc_monthly)
normalized_cross_cov_CESM_4PIC_SAT_precip_monthly = normalize_matrix(cross_cov_CESM_4PIC_SAT_precip_monthly)
normalized_cross_cov_CESM_4PIC_SST_d18Oc_monthly = normalize_matrix(cross_cov_CESM_4PIC_SST_d18Oc_monthly)
normalized_cross_cov_CESM_4PIC_SST_precip_monthly = normalize_matrix(cross_cov_CESM_4PIC_SST_precip_monthly)
normalized_cross_cov_CESM_4PIC_d18Oc_precip_monthly = normalize_matrix(cross_cov_CESM_4PIC_d18Oc_precip_monthly)

# Combine the normalized submatrices into a single normalized covariance matrix
normalized_cov_combined_CESM_4PIC_monthly = np.block([
    [normalized_cov_CESM_4PIC_SAT_D47_monthly, normalized_cross_cov_CESM_4PIC_SAT_SST_D47_monthly, normalized_cross_cov_CESM_4PIC_SAT_d18Oc_monthly, normalized_cross_cov_CESM_4PIC_SAT_precip_monthly],
    [normalized_cross_cov_CESM_4PIC_SAT_SST_D47_monthly.T, normalized_cov_CESM_4PIC_SST_D47_monthly, normalized_cross_cov_CESM_4PIC_SST_d18Oc_monthly, normalized_cross_cov_CESM_4PIC_SST_precip_monthly],
    [normalized_cross_cov_CESM_4PIC_SAT_d18Oc_monthly.T, normalized_cross_cov_CESM_4PIC_SST_d18Oc_monthly.T, normalized_cov_CESM_4PIC_d18Oc_monthly, normalized_cross_cov_CESM_4PIC_d18Oc_precip_monthly],
    [normalized_cross_cov_CESM_4PIC_SAT_precip_monthly.T, normalized_cross_cov_CESM_4PIC_SST_precip_monthly.T, normalized_cross_cov_CESM_4PIC_d18Oc_precip_monthly.T, normalized_cov_CESM_4PIC_precip_monthly]
])

# Plot the heatmap of the normalized combined covariance matrix
plt.figure(figsize=(12, 10))
sns.heatmap(
    normalized_cov_combined_CESM_4PIC_monthly,
    annot=False,
    fmt=".2f",
    cmap="coolwarm",
    center=0,
    xticklabels=SAT_D47_CESM_4PIC_columns_monthly + SST_D47_CESM_4PIC_columns_monthly + d18Oc_CESM_4PIC_columns_monthly + precip_CESM_4PIC_columns_monthly,
    yticklabels=SAT_D47_CESM_4PIC_columns_monthly + SST_D47_CESM_4PIC_columns_monthly + d18Oc_CESM_4PIC_columns_monthly + precip_CESM_4PIC_columns_monthly
)

# Add titles to the axes per parameter
plt.axvline(x=len(SAT_D47_CESM_4PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_CESM_4PIC_columns_monthly) + len(SST_D47_CESM_4PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_CESM_4PIC_columns_monthly) + len(SST_D47_CESM_4PIC_columns_monthly) + len(d18Oc_CESM_4PIC_columns_monthly), color='black', linestyle='--', linewidth=1)

plt.axhline(y=len(SAT_D47_CESM_4PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_CESM_4PIC_columns_monthly) + len(SST_D47_CESM_4PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_CESM_4PIC_columns_monthly) + len(SST_D47_CESM_4PIC_columns_monthly) + len(d18Oc_CESM_4PIC_columns_monthly), color='black', linestyle='--', linewidth=1)

# Add parameter labels
plt.text(len(SAT_D47_CESM_4PIC_columns_monthly) / 2, -2, 'D47 value from SAT', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_CESM_4PIC_columns_monthly) + len(SST_D47_CESM_4PIC_columns_monthly) / 2, -2, 'D47 value from SST', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_CESM_4PIC_columns_monthly) + len(SST_D47_CESM_4PIC_columns_monthly) + len(d18Oc_CESM_4PIC_columns_monthly) / 2, -2, 'd18Oc', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_CESM_4PIC_columns_monthly) + len(SST_D47_CESM_4PIC_columns_monthly) + len(d18Oc_CESM_4PIC_columns_monthly) + len(precip_CESM_4PIC_columns_monthly) / 2, -2, 'Precipitation', ha='center', va='center', fontsize=10)

plt.text(-7, len(SAT_D47_CESM_4PIC_columns_monthly) / 2, 'D47 value from SAT', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-7, len(SAT_D47_CESM_4PIC_columns_monthly) + len(SST_D47_CESM_4PIC_columns_monthly) / 2, 'D47 value from SST', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-7, len(SAT_D47_CESM_4PIC_columns_monthly) + len(SST_D47_CESM_4PIC_columns_monthly) + len(d18Oc_CESM_4PIC_columns_monthly) / 2, 'd18Oc', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-7, len(SAT_D47_CESM_4PIC_columns_monthly) + len(SST_D47_CESM_4PIC_columns_monthly) + len(d18Oc_CESM_4PIC_columns_monthly) + len(precip_CESM_4PIC_columns_monthly) / 2, 'Precipitation', ha='center', va='center', rotation=90, fontsize=10)

plt.title("Normalized Combined Covariance Matrix (CESM 4x preindustrial pCO2)")
plt.show()
No description has been provided for this image

CESM with 2x preindustrial pCO2¶

In [48]:
# Extract the relevant columns for SAT, SST D47, d18Oc, and precipitation
SAT_D47_CESM_2PIC_columns_monthly = [f"{month}_SAT_D47" for month in months]
SST_D47_CESM_2PIC_columns_monthly = [f"{month}_SST_D47" for month in months]
d18Oc_CESM_2PIC_columns_monthly = [f"{month}_d18Oc" for month in months]
precip_CESM_2PIC_columns_monthly = [f"{month}_precip" for month in months]

# Combine the relevant columns into a single dataframe
combined_data_CESM_2PIC_monthly = Lutetian_CESM_2PIC_model[SAT_D47_CESM_2PIC_columns_monthly + SST_D47_CESM_2PIC_columns_monthly + d18Oc_CESM_2PIC_columns_monthly + precip_CESM_2PIC_columns_monthly]

# Calculate the covariance matrix for the combined data
cov_combined_CESM_2PIC_monthly = np.cov(combined_data_CESM_2PIC_monthly.dropna(), rowvar=False)

# Extract the covariance matrices for SAT D47, SST D47, d18Oc, and precipitation
cov_CESM_2PIC_SAT_D47_monthly = cov_combined_CESM_2PIC_monthly[:len(months), :len(months)]
cov_CESM_2PIC_SST_D47_monthly = cov_combined_CESM_2PIC_monthly[len(months):2*len(months), len(months):2*len(months)]
cov_CESM_2PIC_d18Oc_monthly = cov_combined_CESM_2PIC_monthly[2*len(months):3*len(months), 2*len(months):3*len(months)]
cov_CESM_2PIC_precip_monthly = cov_combined_CESM_2PIC_monthly[3*len(months):, 3*len(months):]

# Extract the cross-covariance matrices
cross_cov_CESM_2PIC_SAT_SST_D47_monthly = cov_combined_CESM_2PIC_monthly[:len(months), len(months):2*len(months)]
cross_cov_CESM_2PIC_SAT_d18Oc_monthly = cov_combined_CESM_2PIC_monthly[:len(months), 2*len(months):3*len(months)]
cross_cov_CESM_2PIC_SAT_precip_monthly = cov_combined_CESM_2PIC_monthly[:len(months), 3*len(months):]
cross_cov_CESM_2PIC_SST_d18Oc_monthly = cov_combined_CESM_2PIC_monthly[len(months):2*len(months), 2*len(months):3*len(months)]
cross_cov_CESM_2PIC_SST_precip_monthly = cov_combined_CESM_2PIC_monthly[len(months):2*len(months), 3*len(months):]
cross_cov_CESM_2PIC_d18Oc_precip_monthly = cov_combined_CESM_2PIC_monthly[2*len(months):3*len(months), 3*len(months):]

# Normalize each submatrix
normalized_cov_CESM_2PIC_SAT_D47_monthly = normalize_matrix(cov_CESM_2PIC_SAT_D47_monthly)
normalized_cov_CESM_2PIC_SST_D47_monthly = normalize_matrix(cov_CESM_2PIC_SST_D47_monthly)
normalized_cov_CESM_2PIC_d18Oc_monthly = normalize_matrix(cov_CESM_2PIC_d18Oc_monthly)
normalized_cov_CESM_2PIC_precip_monthly = normalize_matrix(cov_CESM_2PIC_precip_monthly)

# Normalize each cross-covariance matrix
normalized_cross_cov_CESM_2PIC_SAT_SST_D47_monthly = normalize_matrix(cross_cov_CESM_2PIC_SAT_SST_D47_monthly)
normalized_cross_cov_CESM_2PIC_SAT_d18Oc_monthly = normalize_matrix(cross_cov_CESM_2PIC_SAT_d18Oc_monthly)
normalized_cross_cov_CESM_2PIC_SAT_precip_monthly = normalize_matrix(cross_cov_CESM_2PIC_SAT_precip_monthly)
normalized_cross_cov_CESM_2PIC_SST_d18Oc_monthly = normalize_matrix(cross_cov_CESM_2PIC_SST_d18Oc_monthly)
normalized_cross_cov_CESM_2PIC_SST_precip_monthly = normalize_matrix(cross_cov_CESM_2PIC_SST_precip_monthly)
normalized_cross_cov_CESM_2PIC_d18Oc_precip_monthly = normalize_matrix(cross_cov_CESM_2PIC_d18Oc_precip_monthly)

# Combine the normalized submatrices into a single normalized covariance matrix
normalized_cov_combined_CESM_2PIC_monthly = np.block([
    [normalized_cov_CESM_2PIC_SAT_D47_monthly, normalized_cross_cov_CESM_2PIC_SAT_SST_D47_monthly, normalized_cross_cov_CESM_2PIC_SAT_d18Oc_monthly, normalized_cross_cov_CESM_2PIC_SAT_precip_monthly],
    [normalized_cross_cov_CESM_2PIC_SAT_SST_D47_monthly.T, normalized_cov_CESM_2PIC_SST_D47_monthly, normalized_cross_cov_CESM_2PIC_SST_d18Oc_monthly, normalized_cross_cov_CESM_2PIC_SST_precip_monthly],
    [normalized_cross_cov_CESM_2PIC_SAT_d18Oc_monthly.T, normalized_cross_cov_CESM_2PIC_SST_d18Oc_monthly.T, normalized_cov_CESM_2PIC_d18Oc_monthly, normalized_cross_cov_CESM_2PIC_d18Oc_precip_monthly],
    [normalized_cross_cov_CESM_2PIC_SAT_precip_monthly.T, normalized_cross_cov_CESM_2PIC_SST_precip_monthly.T, normalized_cross_cov_CESM_2PIC_d18Oc_precip_monthly.T, normalized_cov_CESM_2PIC_precip_monthly]
])

# Plot the heatmap of the normalized combined covariance matrix
plt.figure(figsize=(12, 10))
sns.heatmap(
    normalized_cov_combined_CESM_2PIC_monthly,
    annot=False,
    fmt=".2f",
    cmap="coolwarm",
    center=0,
    xticklabels=SAT_D47_CESM_2PIC_columns_monthly + SST_D47_CESM_2PIC_columns_monthly + d18Oc_CESM_2PIC_columns_monthly + precip_CESM_2PIC_columns_monthly,
    yticklabels=SAT_D47_CESM_2PIC_columns_monthly + SST_D47_CESM_2PIC_columns_monthly + d18Oc_CESM_2PIC_columns_monthly + precip_CESM_2PIC_columns_monthly
)

# Add titles to the axes per parameter
plt.axvline(x=len(SAT_D47_CESM_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly) + len(d18Oc_CESM_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)

plt.axhline(y=len(SAT_D47_CESM_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly) + len(d18Oc_CESM_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)

# Add parameter labels
plt.text(len(SAT_D47_CESM_2PIC_columns_monthly) / 2, -2, 'D47 value from SAT', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly) / 2, -2, 'D47 value from SST', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly) + len(d18Oc_CESM_2PIC_columns_monthly) / 2, -2, 'd18Oc', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly) + len(d18Oc_CESM_2PIC_columns_monthly) + len(precip_CESM_2PIC_columns_monthly) / 2, -2, 'Precipitation', ha='center', va='center', fontsize=10)

plt.text(-7, len(SAT_D47_CESM_2PIC_columns_monthly) / 2, 'D47 value from SAT', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-7, len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly) / 2, 'D47 value from SST', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-7, len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly) + len(d18Oc_CESM_2PIC_columns_monthly) / 2, 'd18Oc', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-7, len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly) + len(d18Oc_CESM_2PIC_columns_monthly) + len(precip_CESM_2PIC_columns_monthly) / 2, 'Precipitation', ha='center', va='center', rotation=90, fontsize=10)

plt.title("Normalized Combined Covariance Matrix (CESM 2x preindustrial pCO2)")
plt.show()
No description has been provided for this image

HadCM with 1x preindustrial pCO2¶

In [49]:
# Extract the relevant columns for SAT, SST D47, d18Oc, and precipitation
SAT_D47_HadCM_new_1PIC_columns_monthly = [f"{month}_SAT_D47" for month in months]
SST_D47_HadCM_new_1PIC_columns_monthly = [f"{month}_SST_D47" for month in months]
d18Oc_HadCM_new_1PIC_columns_monthly = [f"{month}_d18Oc" for month in months]
precip_HadCM_new_1PIC_columns_monthly = [f"{month}_precip" for month in months]

# Combine the relevant columns into a single dataframe
combined_data_HadCM_new_1PIC_monthly = Lutetian_HadCM_new_1PIC_model[SAT_D47_HadCM_new_1PIC_columns_monthly + SST_D47_HadCM_new_1PIC_columns_monthly + d18Oc_HadCM_new_1PIC_columns_monthly + precip_HadCM_new_1PIC_columns_monthly]

# Calculate the covariance matrix for the combined data
cov_combined_HadCM_new_1PIC_monthly = np.cov(combined_data_HadCM_new_1PIC_monthly.dropna(), rowvar=False)

# Extract the covariance matrices for SAT D47, SST D47, d18Oc, and precipitation
cov_HadCM_new_1PIC_SAT_D47_monthly = cov_combined_HadCM_new_1PIC_monthly[:len(months), :len(months)]
cov_HadCM_new_1PIC_SST_D47_monthly = cov_combined_HadCM_new_1PIC_monthly[len(months):2*len(months), len(months):2*len(months)]
cov_HadCM_new_1PIC_d18Oc_monthly = cov_combined_HadCM_new_1PIC_monthly[2*len(months):3*len(months), 2*len(months):3*len(months)]
cov_HadCM_new_1PIC_precip_monthly = cov_combined_HadCM_new_1PIC_monthly[3*len(months):, 3*len(months):]

# Extract the cross-covariance matrices
cross_cov_HadCM_new_1PIC_SAT_SST_D47_monthly = cov_combined_HadCM_new_1PIC_monthly[:len(months), len(months):2*len(months)]
cross_cov_HadCM_new_1PIC_SAT_d18Oc_monthly = cov_combined_HadCM_new_1PIC_monthly[:len(months), 2*len(months):3*len(months)]
cross_cov_HadCM_new_1PIC_SAT_precip_monthly = cov_combined_HadCM_new_1PIC_monthly[:len(months), 3*len(months):]
cross_cov_HadCM_new_1PIC_SST_d18Oc_monthly = cov_combined_HadCM_new_1PIC_monthly[len(months):2*len(months), 2*len(months):3*len(months)]
cross_cov_HadCM_new_1PIC_SST_precip_monthly = cov_combined_HadCM_new_1PIC_monthly[len(months):2*len(months), 3*len(months):]
cross_cov_HadCM_new_1PIC_d18Oc_precip_monthly = cov_combined_HadCM_new_1PIC_monthly[2*len(months):3*len(months), 3*len(months):]

# Normalize each submatrix
normalized_cov_HadCM_new_1PIC_SAT_D47_monthly = normalize_matrix(cov_HadCM_new_1PIC_SAT_D47_monthly)
normalized_cov_HadCM_new_1PIC_SST_D47_monthly = normalize_matrix(cov_HadCM_new_1PIC_SST_D47_monthly)
normalized_cov_HadCM_new_1PIC_d18Oc_monthly = normalize_matrix(cov_HadCM_new_1PIC_d18Oc_monthly)
normalized_cov_HadCM_new_1PIC_precip_monthly = normalize_matrix(cov_HadCM_new_1PIC_precip_monthly)

# Normalize each cross-covariance matrix
normalized_cross_cov_HadCM_new_1PIC_SAT_SST_D47_monthly = normalize_matrix(cross_cov_HadCM_new_1PIC_SAT_SST_D47_monthly)
normalized_cross_cov_HadCM_new_1PIC_SAT_d18Oc_monthly = normalize_matrix(cross_cov_HadCM_new_1PIC_SAT_d18Oc_monthly)
normalized_cross_cov_HadCM_new_1PIC_SAT_precip_monthly = normalize_matrix(cross_cov_HadCM_new_1PIC_SAT_precip_monthly)
normalized_cross_cov_HadCM_new_1PIC_SST_d18Oc_monthly = normalize_matrix(cross_cov_HadCM_new_1PIC_SST_d18Oc_monthly)
normalized_cross_cov_HadCM_new_1PIC_SST_precip_monthly = normalize_matrix(cross_cov_HadCM_new_1PIC_SST_precip_monthly)
normalized_cross_cov_HadCM_new_1PIC_d18Oc_precip_monthly = normalize_matrix(cross_cov_HadCM_new_1PIC_d18Oc_precip_monthly)

# Combine the normalized submatrices into a single normalized covariance matrix
normalized_cov_combined_HadCM_new_1PIC_monthly = np.block([
    [normalized_cov_HadCM_new_1PIC_SAT_D47_monthly, normalized_cross_cov_HadCM_new_1PIC_SAT_SST_D47_monthly, normalized_cross_cov_HadCM_new_1PIC_SAT_d18Oc_monthly, normalized_cross_cov_HadCM_new_1PIC_SAT_precip_monthly],
    [normalized_cross_cov_HadCM_new_1PIC_SAT_SST_D47_monthly.T, normalized_cov_HadCM_new_1PIC_SST_D47_monthly, normalized_cross_cov_HadCM_new_1PIC_SST_d18Oc_monthly, normalized_cross_cov_HadCM_new_1PIC_SST_precip_monthly],
    [normalized_cross_cov_HadCM_new_1PIC_SAT_d18Oc_monthly.T, normalized_cross_cov_HadCM_new_1PIC_SST_d18Oc_monthly.T, normalized_cov_HadCM_new_1PIC_d18Oc_monthly, normalized_cross_cov_HadCM_new_1PIC_d18Oc_precip_monthly],
    [normalized_cross_cov_HadCM_new_1PIC_SAT_precip_monthly.T, normalized_cross_cov_HadCM_new_1PIC_SST_precip_monthly.T, normalized_cross_cov_HadCM_new_1PIC_d18Oc_precip_monthly.T, normalized_cov_HadCM_new_1PIC_precip_monthly]
])

# Plot the heatmap of the normalized combined covariance matrix
plt.figure(figsize=(12, 10))
sns.heatmap(
    normalized_cov_combined_HadCM_new_1PIC_monthly,
    annot=False,
    fmt=".2f",
    cmap="coolwarm",
    center=0,
    xticklabels=SAT_D47_HadCM_new_1PIC_columns_monthly + SST_D47_HadCM_new_1PIC_columns_monthly + d18Oc_HadCM_new_1PIC_columns_monthly + precip_HadCM_new_1PIC_columns_monthly,
    yticklabels=SAT_D47_HadCM_new_1PIC_columns_monthly + SST_D47_HadCM_new_1PIC_columns_monthly + d18Oc_HadCM_new_1PIC_columns_monthly + precip_HadCM_new_1PIC_columns_monthly
)

# Add titles to the axes per parameter
plt.axvline(x=len(SAT_D47_HadCM_new_1PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_HadCM_new_1PIC_columns_monthly) + len(SST_D47_HadCM_new_1PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_HadCM_new_1PIC_columns_monthly) + len(SST_D47_HadCM_new_1PIC_columns_monthly) + len(d18Oc_HadCM_new_1PIC_columns_monthly), color='black', linestyle='--', linewidth=1)

plt.axhline(y=len(SAT_D47_HadCM_new_1PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_HadCM_new_1PIC_columns_monthly) + len(SST_D47_HadCM_new_1PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_HadCM_new_1PIC_columns_monthly) + len(SST_D47_HadCM_new_1PIC_columns_monthly) + len(d18Oc_HadCM_new_1PIC_columns_monthly), color='black', linestyle='--', linewidth=1)

# Add parameter labels
plt.text(len(SAT_D47_HadCM_new_1PIC_columns_monthly) / 2, -2, 'D47 value from SAT', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_new_1PIC_columns_monthly) + len(SST_D47_HadCM_new_1PIC_columns_monthly) / 2, -2, 'D47 value from SST', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_new_1PIC_columns_monthly) + len(SST_D47_HadCM_new_1PIC_columns_monthly) + len(d18Oc_HadCM_new_1PIC_columns_monthly) / 2, -2, 'd18Oc', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_new_1PIC_columns_monthly) + len(SST_D47_HadCM_new_1PIC_columns_monthly) + len(d18Oc_HadCM_new_1PIC_columns_monthly) + len(precip_HadCM_new_1PIC_columns_monthly) / 2, -2, 'Precipitation', ha='center', va='center', fontsize=10)

plt.text(-7, len(SAT_D47_HadCM_new_1PIC_columns_monthly) / 2, 'D47 value from SAT', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-7, len(SAT_D47_HadCM_new_1PIC_columns_monthly) + len(SST_D47_HadCM_new_1PIC_columns_monthly) / 2, 'D47 value from SST', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-7, len(SAT_D47_HadCM_new_1PIC_columns_monthly) + len(SST_D47_HadCM_new_1PIC_columns_monthly) + len(d18Oc_HadCM_new_1PIC_columns_monthly) / 2, 'd18Oc', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-7, len(SAT_D47_HadCM_new_1PIC_columns_monthly) + len(SST_D47_HadCM_new_1PIC_columns_monthly) + len(d18Oc_HadCM_new_1PIC_columns_monthly) + len(precip_HadCM_new_1PIC_columns_monthly) / 2, 'Precipitation', ha='center', va='center', rotation=90, fontsize=10)

plt.title("Normalized Combined Covariance Matrix (HadCM (new) 1x preindustrial pCO2)")
plt.show()
No description has been provided for this image

HadCM with 2x preindustrial pCO2¶

In [50]:
# Extract the relevant columns for SAT, SST D47, d18Oc, and precipitation
SAT_D47_HadCM_new_2PIC_columns_monthly = [f"{month}_SAT_D47" for month in months]
SST_D47_HadCM_new_2PIC_columns_monthly = [f"{month}_SST_D47" for month in months]
d18Oc_HadCM_new_2PIC_columns_monthly = [f"{month}_d18Oc" for month in months]
precip_HadCM_new_2PIC_columns_monthly = [f"{month}_precip" for month in months]

# Combine the relevant columns into a single dataframe
combined_data_HadCM_new_2PIC_monthly = Lutetian_HadCM_new_2PIC_model[SAT_D47_HadCM_new_2PIC_columns_monthly + SST_D47_HadCM_new_2PIC_columns_monthly + d18Oc_HadCM_new_2PIC_columns_monthly + precip_HadCM_new_2PIC_columns_monthly]

# Calculate the covariance matrix for the combined data
cov_combined_HadCM_new_2PIC_monthly = np.cov(combined_data_HadCM_new_2PIC_monthly.dropna(), rowvar=False)

# Extract the covariance matrices for SAT D47, SST D47, d18Oc, and precipitation
cov_HadCM_new_2PIC_SAT_D47_monthly = cov_combined_HadCM_new_2PIC_monthly[:len(months), :len(months)]
cov_HadCM_new_2PIC_SST_D47_monthly = cov_combined_HadCM_new_2PIC_monthly[len(months):2*len(months), len(months):2*len(months)]
cov_HadCM_new_2PIC_d18Oc_monthly = cov_combined_HadCM_new_2PIC_monthly[2*len(months):3*len(months), 2*len(months):3*len(months)]
cov_HadCM_new_2PIC_precip_monthly = cov_combined_HadCM_new_2PIC_monthly[3*len(months):, 3*len(months):]

# Extract the cross-covariance matrices
cross_cov_HadCM_new_2PIC_SAT_SST_D47_monthly = cov_combined_HadCM_new_2PIC_monthly[:len(months), len(months):2*len(months)]
cross_cov_HadCM_new_2PIC_SAT_d18Oc_monthly = cov_combined_HadCM_new_2PIC_monthly[:len(months), 2*len(months):3*len(months)]
cross_cov_HadCM_new_2PIC_SAT_precip_monthly = cov_combined_HadCM_new_2PIC_monthly[:len(months), 3*len(months):]
cross_cov_HadCM_new_2PIC_SST_d18Oc_monthly = cov_combined_HadCM_new_2PIC_monthly[len(months):2*len(months), 2*len(months):3*len(months)]
cross_cov_HadCM_new_2PIC_SST_precip_monthly = cov_combined_HadCM_new_2PIC_monthly[len(months):2*len(months), 3*len(months):]
cross_cov_HadCM_new_2PIC_d18Oc_precip_monthly = cov_combined_HadCM_new_2PIC_monthly[2*len(months):3*len(months), 3*len(months):]

# Normalize each submatrix
normalized_cov_HadCM_new_2PIC_SAT_D47_monthly = normalize_matrix(cov_HadCM_new_2PIC_SAT_D47_monthly)
normalized_cov_HadCM_new_2PIC_SST_D47_monthly = normalize_matrix(cov_HadCM_new_2PIC_SST_D47_monthly)
normalized_cov_HadCM_new_2PIC_d18Oc_monthly = normalize_matrix(cov_HadCM_new_2PIC_d18Oc_monthly)
normalized_cov_HadCM_new_2PIC_precip_monthly = normalize_matrix(cov_HadCM_new_2PIC_precip_monthly)

# Normalize each cross-covariance matrix
normalized_cross_cov_HadCM_new_2PIC_SAT_SST_D47_monthly = normalize_matrix(cross_cov_HadCM_new_2PIC_SAT_SST_D47_monthly)
normalized_cross_cov_HadCM_new_2PIC_SAT_d18Oc_monthly = normalize_matrix(cross_cov_HadCM_new_2PIC_SAT_d18Oc_monthly)
normalized_cross_cov_HadCM_new_2PIC_SAT_precip_monthly = normalize_matrix(cross_cov_HadCM_new_2PIC_SAT_precip_monthly)
normalized_cross_cov_HadCM_new_2PIC_SST_d18Oc_monthly = normalize_matrix(cross_cov_HadCM_new_2PIC_SST_d18Oc_monthly)
normalized_cross_cov_HadCM_new_2PIC_SST_precip_monthly = normalize_matrix(cross_cov_HadCM_new_2PIC_SST_precip_monthly)
normalized_cross_cov_HadCM_new_2PIC_d18Oc_precip_monthly = normalize_matrix(cross_cov_HadCM_new_2PIC_d18Oc_precip_monthly)

# Combine the normalized submatrices into a single normalized covariance matrix
normalized_cov_combined_HadCM_new_2PIC_monthly = np.block([
    [normalized_cov_HadCM_new_2PIC_SAT_D47_monthly, normalized_cross_cov_HadCM_new_2PIC_SAT_SST_D47_monthly, normalized_cross_cov_HadCM_new_2PIC_SAT_d18Oc_monthly, normalized_cross_cov_HadCM_new_2PIC_SAT_precip_monthly],
    [normalized_cross_cov_HadCM_new_2PIC_SAT_SST_D47_monthly.T, normalized_cov_HadCM_new_2PIC_SST_D47_monthly, normalized_cross_cov_HadCM_new_2PIC_SST_d18Oc_monthly, normalized_cross_cov_HadCM_new_2PIC_SST_precip_monthly],
    [normalized_cross_cov_HadCM_new_2PIC_SAT_d18Oc_monthly.T, normalized_cross_cov_HadCM_new_2PIC_SST_d18Oc_monthly.T, normalized_cov_HadCM_new_2PIC_d18Oc_monthly, normalized_cross_cov_HadCM_new_2PIC_d18Oc_precip_monthly],
    [normalized_cross_cov_HadCM_new_2PIC_SAT_precip_monthly.T, normalized_cross_cov_HadCM_new_2PIC_SST_precip_monthly.T, normalized_cross_cov_HadCM_new_2PIC_d18Oc_precip_monthly.T, normalized_cov_HadCM_new_2PIC_precip_monthly]
])

# Plot the heatmap of the normalized combined covariance matrix
plt.figure(figsize=(12, 10))
sns.heatmap(
    normalized_cov_combined_HadCM_new_2PIC_monthly,
    annot=False,
    fmt=".2f",
    cmap="coolwarm",
    center=0,
    xticklabels=SAT_D47_HadCM_new_2PIC_columns_monthly + SST_D47_HadCM_new_2PIC_columns_monthly + d18Oc_HadCM_new_2PIC_columns_monthly + precip_HadCM_new_2PIC_columns_monthly,
    yticklabels=SAT_D47_HadCM_new_2PIC_columns_monthly + SST_D47_HadCM_new_2PIC_columns_monthly + d18Oc_HadCM_new_2PIC_columns_monthly + precip_HadCM_new_2PIC_columns_monthly
)

# Add titles to the axes per parameter
plt.axvline(x=len(SAT_D47_HadCM_new_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_HadCM_new_2PIC_columns_monthly) + len(SST_D47_HadCM_new_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_HadCM_new_2PIC_columns_monthly) + len(SST_D47_HadCM_new_2PIC_columns_monthly) + len(d18Oc_HadCM_new_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)

plt.axhline(y=len(SAT_D47_HadCM_new_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_HadCM_new_2PIC_columns_monthly) + len(SST_D47_HadCM_new_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_HadCM_new_2PIC_columns_monthly) + len(SST_D47_HadCM_new_2PIC_columns_monthly) + len(d18Oc_HadCM_new_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)

# Add parameter labels
plt.text(len(SAT_D47_HadCM_new_2PIC_columns_monthly) / 2, -2, 'D47 value from SAT', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_new_2PIC_columns_monthly) + len(SST_D47_HadCM_new_2PIC_columns_monthly) / 2, -2, 'D47 value from SST', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_new_2PIC_columns_monthly) + len(SST_D47_HadCM_new_2PIC_columns_monthly) + len(d18Oc_HadCM_new_2PIC_columns_monthly) / 2, -2, 'd18Oc', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_new_2PIC_columns_monthly) + len(SST_D47_HadCM_new_2PIC_columns_monthly) + len(d18Oc_HadCM_new_2PIC_columns_monthly) + len(precip_HadCM_new_2PIC_columns_monthly) / 2, -2, 'Precipitation', ha='center', va='center', fontsize=10)

plt.text(-7, len(SAT_D47_HadCM_new_2PIC_columns_monthly) / 2, 'D47 value from SAT', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-7, len(SAT_D47_HadCM_new_2PIC_columns_monthly) + len(SST_D47_HadCM_new_2PIC_columns_monthly) / 2, 'D47 value from SST', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-7, len(SAT_D47_HadCM_new_2PIC_columns_monthly) + len(SST_D47_HadCM_new_2PIC_columns_monthly) + len(d18Oc_HadCM_new_2PIC_columns_monthly) / 2, 'd18Oc', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-7, len(SAT_D47_HadCM_new_2PIC_columns_monthly) + len(SST_D47_HadCM_new_2PIC_columns_monthly) + len(d18Oc_HadCM_new_2PIC_columns_monthly) + len(precip_HadCM_new_2PIC_columns_monthly) / 2, 'Precipitation', ha='center', va='center', rotation=90, fontsize=10)

plt.title("Normalized Combined Covariance Matrix (HadCM (new) 2x preindustrial pCO2)")
plt.show()
No description has been provided for this image

HadCM with 1056 ppm pCO2¶

In [51]:
# Extract the relevant columns for SAT, SST D47, d18Oc, and precipitation
SAT_D47_HadCM_new_1056ppm_columns_monthly = [f"{month}_SAT_D47" for month in months]
SST_D47_HadCM_new_1056ppm_columns_monthly = [f"{month}_SST_D47" for month in months]
d18Oc_HadCM_new_1056ppm_columns_monthly = [f"{month}_d18Oc" for month in months]
precip_HadCM_new_1056ppm_columns_monthly = [f"{month}_precip" for month in months]

# Combine the relevant columns into a single dataframe
combined_data_HadCM_new_1056ppm_monthly = Lutetian_HadCM_new_1056ppm_model[SAT_D47_HadCM_new_1056ppm_columns_monthly + SST_D47_HadCM_new_1056ppm_columns_monthly + d18Oc_HadCM_new_1056ppm_columns_monthly + precip_HadCM_new_1056ppm_columns_monthly]

# Calculate the covariance matrix for the combined data
cov_combined_HadCM_new_1056ppm_monthly = np.cov(combined_data_HadCM_new_1056ppm_monthly.dropna(), rowvar=False)

# Extract the covariance matrices for SAT D47, SST D47, d18Oc, and precipitation
cov_HadCM_new_1056ppm_SAT_D47_monthly = cov_combined_HadCM_new_1056ppm_monthly[:len(months), :len(months)]
cov_HadCM_new_1056ppm_SST_D47_monthly = cov_combined_HadCM_new_1056ppm_monthly[len(months):2*len(months), len(months):2*len(months)]
cov_HadCM_new_1056ppm_d18Oc_monthly = cov_combined_HadCM_new_1056ppm_monthly[2*len(months):3*len(months), 2*len(months):3*len(months)]
cov_HadCM_new_1056ppm_precip_monthly = cov_combined_HadCM_new_1056ppm_monthly[3*len(months):, 3*len(months):]

# Extract the cross-covariance matrices
cross_cov_HadCM_new_1056ppm_SAT_SST_D47_monthly = cov_combined_HadCM_new_1056ppm_monthly[:len(months), len(months):2*len(months)]
cross_cov_HadCM_new_1056ppm_SAT_d18Oc_monthly = cov_combined_HadCM_new_1056ppm_monthly[:len(months), 2*len(months):3*len(months)]
cross_cov_HadCM_new_1056ppm_SAT_precip_monthly = cov_combined_HadCM_new_1056ppm_monthly[:len(months), 3*len(months):]
cross_cov_HadCM_new_1056ppm_SST_d18Oc_monthly = cov_combined_HadCM_new_1056ppm_monthly[len(months):2*len(months), 2*len(months):3*len(months)]
cross_cov_HadCM_new_1056ppm_SST_precip_monthly = cov_combined_HadCM_new_1056ppm_monthly[len(months):2*len(months), 3*len(months):]
cross_cov_HadCM_new_1056ppm_d18Oc_precip_monthly = cov_combined_HadCM_new_1056ppm_monthly[2*len(months):3*len(months), 3*len(months):]

# Normalize each submatrix
normalized_cov_HadCM_new_1056ppm_SAT_D47_monthly = normalize_matrix(cov_HadCM_new_1056ppm_SAT_D47_monthly)
normalized_cov_HadCM_new_1056ppm_SST_D47_monthly = normalize_matrix(cov_HadCM_new_1056ppm_SST_D47_monthly)
normalized_cov_HadCM_new_1056ppm_d18Oc_monthly = normalize_matrix(cov_HadCM_new_1056ppm_d18Oc_monthly)
normalized_cov_HadCM_new_1056ppm_precip_monthly = normalize_matrix(cov_HadCM_new_1056ppm_precip_monthly)

# Normalize each cross-covariance matrix
normalized_cross_cov_HadCM_new_1056ppm_SAT_SST_D47_monthly = normalize_matrix(cross_cov_HadCM_new_1056ppm_SAT_SST_D47_monthly)
normalized_cross_cov_HadCM_new_1056ppm_SAT_d18Oc_monthly = normalize_matrix(cross_cov_HadCM_new_1056ppm_SAT_d18Oc_monthly)
normalized_cross_cov_HadCM_new_1056ppm_SAT_precip_monthly = normalize_matrix(cross_cov_HadCM_new_1056ppm_SAT_precip_monthly)
normalized_cross_cov_HadCM_new_1056ppm_SST_d18Oc_monthly = normalize_matrix(cross_cov_HadCM_new_1056ppm_SST_d18Oc_monthly)
normalized_cross_cov_HadCM_new_1056ppm_SST_precip_monthly = normalize_matrix(cross_cov_HadCM_new_1056ppm_SST_precip_monthly)
normalized_cross_cov_HadCM_new_1056ppm_d18Oc_precip_monthly = normalize_matrix(cross_cov_HadCM_new_1056ppm_d18Oc_precip_monthly)

# Combine the normalized submatrices into a single normalized covariance matrix
normalized_cov_combined_HadCM_new_1056ppm_monthly = np.block([
    [normalized_cov_HadCM_new_1056ppm_SAT_D47_monthly, normalized_cross_cov_HadCM_new_1056ppm_SAT_SST_D47_monthly, normalized_cross_cov_HadCM_new_1056ppm_SAT_d18Oc_monthly, normalized_cross_cov_HadCM_new_1056ppm_SAT_precip_monthly],
    [normalized_cross_cov_HadCM_new_1056ppm_SAT_SST_D47_monthly.T, normalized_cov_HadCM_new_1056ppm_SST_D47_monthly, normalized_cross_cov_HadCM_new_1056ppm_SST_d18Oc_monthly, normalized_cross_cov_HadCM_new_1056ppm_SST_precip_monthly],
    [normalized_cross_cov_HadCM_new_1056ppm_SAT_d18Oc_monthly.T, normalized_cross_cov_HadCM_new_1056ppm_SST_d18Oc_monthly.T, normalized_cov_HadCM_new_1056ppm_d18Oc_monthly, normalized_cross_cov_HadCM_new_1056ppm_d18Oc_precip_monthly],
    [normalized_cross_cov_HadCM_new_1056ppm_SAT_precip_monthly.T, normalized_cross_cov_HadCM_new_1056ppm_SST_precip_monthly.T, normalized_cross_cov_HadCM_new_1056ppm_d18Oc_precip_monthly.T, normalized_cov_HadCM_new_1056ppm_precip_monthly]
])

# Plot the heatmap of the normalized combined covariance matrix
plt.figure(figsize=(12, 10))
sns.heatmap(
    normalized_cov_combined_HadCM_new_1056ppm_monthly,
    annot=False,
    fmt=".2f",
    cmap="coolwarm",
    center=0,
    xticklabels=SAT_D47_HadCM_new_1056ppm_columns_monthly + SST_D47_HadCM_new_1056ppm_columns_monthly + d18Oc_HadCM_new_1056ppm_columns_monthly + precip_HadCM_new_1056ppm_columns_monthly,
    yticklabels=SAT_D47_HadCM_new_1056ppm_columns_monthly + SST_D47_HadCM_new_1056ppm_columns_monthly + d18Oc_HadCM_new_1056ppm_columns_monthly + precip_HadCM_new_1056ppm_columns_monthly
)

# Add titles to the axes per parameter
plt.axvline(x=len(SAT_D47_HadCM_new_1056ppm_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_HadCM_new_1056ppm_columns_monthly) + len(SST_D47_HadCM_new_1056ppm_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_HadCM_new_1056ppm_columns_monthly) + len(SST_D47_HadCM_new_1056ppm_columns_monthly) + len(d18Oc_HadCM_new_1056ppm_columns_monthly), color='black', linestyle='--', linewidth=1)

plt.axhline(y=len(SAT_D47_HadCM_new_1056ppm_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_HadCM_new_1056ppm_columns_monthly) + len(SST_D47_HadCM_new_1056ppm_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_HadCM_new_1056ppm_columns_monthly) + len(SST_D47_HadCM_new_1056ppm_columns_monthly) + len(d18Oc_HadCM_new_1056ppm_columns_monthly), color='black', linestyle='--', linewidth=1)

# Add parameter labels
plt.text(len(SAT_D47_HadCM_new_1056ppm_columns_monthly) / 2, -2, 'D47 value from SAT', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_new_1056ppm_columns_monthly) + len(SST_D47_HadCM_new_1056ppm_columns_monthly) / 2, -2, 'D47 value from SST', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_new_1056ppm_columns_monthly) + len(SST_D47_HadCM_new_1056ppm_columns_monthly) + len(d18Oc_HadCM_new_1056ppm_columns_monthly) / 2, -2, 'd18Oc', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_new_1056ppm_columns_monthly) + len(SST_D47_HadCM_new_1056ppm_columns_monthly) + len(d18Oc_HadCM_new_1056ppm_columns_monthly) + len(precip_HadCM_new_1056ppm_columns_monthly) / 2, -2, 'Precipitation', ha='center', va='center', fontsize=10)

plt.text(-7, len(SAT_D47_HadCM_new_1056ppm_columns_monthly) / 2, 'D47 value from SAT', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-7, len(SAT_D47_HadCM_new_1056ppm_columns_monthly) + len(SST_D47_HadCM_new_1056ppm_columns_monthly) / 2, 'D47 value from SST', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-7, len(SAT_D47_HadCM_new_1056ppm_columns_monthly) + len(SST_D47_HadCM_new_1056ppm_columns_monthly) + len(d18Oc_HadCM_new_1056ppm_columns_monthly) / 2, 'd18Oc', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-7, len(SAT_D47_HadCM_new_1056ppm_columns_monthly) + len(SST_D47_HadCM_new_1056ppm_columns_monthly) + len(d18Oc_HadCM_new_1056ppm_columns_monthly) + len(precip_HadCM_new_1056ppm_columns_monthly) / 2, 'Precipitation', ha='center', va='center', rotation=90, fontsize=10)

plt.title("Normalized Combined Covariance Matrix (CESM 2x preindustrial pCO2)")
plt.show()
No description has been provided for this image

HadCM (old) with 2x preindustrial pCO2¶

In [52]:
# Extract the relevant columns for SAT, SST D47, d18Oc, and precipitation
SAT_D47_HadCM_old_2PIC_columns_monthly = [f"{month}_SAT_D47" for month in months]
SST_D47_HadCM_old_2PIC_columns_monthly = [f"{month}_SST_D47" for month in months]
d18Oc_HadCM_old_2PIC_columns_monthly = [f"{month}_d18Oc" for month in months]
precip_HadCM_old_2PIC_columns_monthly = [f"{month}_precip" for month in months]

# Combine the relevant columns into a single dataframe
combined_data_HadCM_old_2PIC_monthly = Lutetian_HadCM_old_2PIC_model[SAT_D47_HadCM_old_2PIC_columns_monthly + SST_D47_HadCM_old_2PIC_columns_monthly + d18Oc_HadCM_old_2PIC_columns_monthly + precip_HadCM_old_2PIC_columns_monthly]

# Calculate the covariance matrix for the combined data
cov_combined_HadCM_old_2PIC_monthly = np.cov(combined_data_HadCM_old_2PIC_monthly.dropna(), rowvar=False)

# Extract the covariance matrices for SAT D47, SST D47, d18Oc, and precipitation
cov_HadCM_old_2PIC_SAT_D47_monthly = cov_combined_HadCM_old_2PIC_monthly[:len(months), :len(months)]
cov_HadCM_old_2PIC_SST_D47_monthly = cov_combined_HadCM_old_2PIC_monthly[len(months):2*len(months), len(months):2*len(months)]
cov_HadCM_old_2PIC_d18Oc_monthly = cov_combined_HadCM_old_2PIC_monthly[2*len(months):3*len(months), 2*len(months):3*len(months)]
cov_HadCM_old_2PIC_precip_monthly = cov_combined_HadCM_old_2PIC_monthly[3*len(months):, 3*len(months):]

# Extract the cross-covariance matrices
cross_cov_HadCM_old_2PIC_SAT_SST_D47_monthly = cov_combined_HadCM_old_2PIC_monthly[:len(months), len(months):2*len(months)]
cross_cov_HadCM_old_2PIC_SAT_d18Oc_monthly = cov_combined_HadCM_old_2PIC_monthly[:len(months), 2*len(months):3*len(months)]
cross_cov_HadCM_old_2PIC_SAT_precip_monthly = cov_combined_HadCM_old_2PIC_monthly[:len(months), 3*len(months):]
cross_cov_HadCM_old_2PIC_SST_d18Oc_monthly = cov_combined_HadCM_old_2PIC_monthly[len(months):2*len(months), 2*len(months):3*len(months)]
cross_cov_HadCM_old_2PIC_SST_precip_monthly = cov_combined_HadCM_old_2PIC_monthly[len(months):2*len(months), 3*len(months):]
cross_cov_HadCM_old_2PIC_d18Oc_precip_monthly = cov_combined_HadCM_old_2PIC_monthly[2*len(months):3*len(months), 3*len(months):]

# Normalize each submatrix
normalized_cov_HadCM_old_2PIC_SAT_D47_monthly = normalize_matrix(cov_HadCM_old_2PIC_SAT_D47_monthly)
normalized_cov_HadCM_old_2PIC_SST_D47_monthly = normalize_matrix(cov_HadCM_old_2PIC_SST_D47_monthly)
normalized_cov_HadCM_old_2PIC_d18Oc_monthly = normalize_matrix(cov_HadCM_old_2PIC_d18Oc_monthly)
normalized_cov_HadCM_old_2PIC_precip_monthly = normalize_matrix(cov_HadCM_old_2PIC_precip_monthly)

# Normalize each cross-covariance matrix
normalized_cross_cov_HadCM_old_2PIC_SAT_SST_D47_monthly = normalize_matrix(cross_cov_HadCM_old_2PIC_SAT_SST_D47_monthly)
normalized_cross_cov_HadCM_old_2PIC_SAT_d18Oc_monthly = normalize_matrix(cross_cov_HadCM_old_2PIC_SAT_d18Oc_monthly)
normalized_cross_cov_HadCM_old_2PIC_SAT_precip_monthly = normalize_matrix(cross_cov_HadCM_old_2PIC_SAT_precip_monthly)
normalized_cross_cov_HadCM_old_2PIC_SST_d18Oc_monthly = normalize_matrix(cross_cov_HadCM_old_2PIC_SST_d18Oc_monthly)
normalized_cross_cov_HadCM_old_2PIC_SST_precip_monthly = normalize_matrix(cross_cov_HadCM_old_2PIC_SST_precip_monthly)
normalized_cross_cov_HadCM_old_2PIC_d18Oc_precip_monthly = normalize_matrix(cross_cov_HadCM_old_2PIC_d18Oc_precip_monthly)

# Combine the normalized submatrices into a single normalized covariance matrix
normalized_cov_combined_HadCM_old_2PIC_monthly = np.block([
    [normalized_cov_HadCM_old_2PIC_SAT_D47_monthly, normalized_cross_cov_HadCM_old_2PIC_SAT_SST_D47_monthly, normalized_cross_cov_HadCM_old_2PIC_SAT_d18Oc_monthly, normalized_cross_cov_HadCM_old_2PIC_SAT_precip_monthly],
    [normalized_cross_cov_HadCM_old_2PIC_SAT_SST_D47_monthly.T, normalized_cov_HadCM_old_2PIC_SST_D47_monthly, normalized_cross_cov_HadCM_old_2PIC_SST_d18Oc_monthly, normalized_cross_cov_HadCM_old_2PIC_SST_precip_monthly],
    [normalized_cross_cov_HadCM_old_2PIC_SAT_d18Oc_monthly.T, normalized_cross_cov_HadCM_old_2PIC_SST_d18Oc_monthly.T, normalized_cov_HadCM_old_2PIC_d18Oc_monthly, normalized_cross_cov_HadCM_old_2PIC_d18Oc_precip_monthly],
    [normalized_cross_cov_HadCM_old_2PIC_SAT_precip_monthly.T, normalized_cross_cov_HadCM_old_2PIC_SST_precip_monthly.T, normalized_cross_cov_HadCM_old_2PIC_d18Oc_precip_monthly.T, normalized_cov_HadCM_old_2PIC_precip_monthly]
])

# Plot the heatmap of the normalized combined covariance matrix
plt.figure(figsize=(12, 10))
sns.heatmap(
    normalized_cov_combined_HadCM_old_2PIC_monthly,
    annot=False,
    fmt=".2f",
    cmap="coolwarm",
    center=0,
    xticklabels=SAT_D47_HadCM_old_2PIC_columns_monthly + SST_D47_HadCM_old_2PIC_columns_monthly + d18Oc_HadCM_old_2PIC_columns_monthly + precip_HadCM_old_2PIC_columns_monthly,
    yticklabels=SAT_D47_HadCM_old_2PIC_columns_monthly + SST_D47_HadCM_old_2PIC_columns_monthly + d18Oc_HadCM_old_2PIC_columns_monthly + precip_HadCM_old_2PIC_columns_monthly
)

# Add titles to the axes per parameter
plt.axvline(x=len(SAT_D47_HadCM_old_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly) + len(d18Oc_HadCM_old_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)

plt.axhline(y=len(SAT_D47_HadCM_old_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly) + len(d18Oc_HadCM_old_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)

# Add parameter labels
plt.text(len(SAT_D47_HadCM_old_2PIC_columns_monthly) / 2, -2, 'D47 value from SAT', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly) / 2, -2, 'D47 value from SST', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly) + len(d18Oc_HadCM_old_2PIC_columns_monthly) / 2, -2, 'd18Oc', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly) + len(d18Oc_HadCM_old_2PIC_columns_monthly) + len(precip_HadCM_old_2PIC_columns_monthly) / 2, -2, 'Precipitation', ha='center', va='center', fontsize=10)

plt.text(-7, len(SAT_D47_HadCM_old_2PIC_columns_monthly) / 2, 'D47 value from SAT', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-7, len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly) / 2, 'D47 value from SST', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-7, len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly) + len(d18Oc_HadCM_old_2PIC_columns_monthly) / 2, 'd18Oc', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-7, len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly) + len(d18Oc_HadCM_old_2PIC_columns_monthly) + len(precip_HadCM_old_2PIC_columns_monthly) / 2, 'Precipitation', ha='center', va='center', rotation=90, fontsize=10)

plt.title("Normalized Combined Covariance Matrix (HadCM (new) 1x preindustrial pCO2)")
plt.show()
No description has been provided for this image

HadCM (old) with 4x preindustrial pCO2¶

In [53]:
# Extract the relevant columns for SAT, SST D47, d18Oc, and precipitation
SAT_D47_HadCM_old_4PIC_columns_monthly = [f"{month}_SAT_D47" for month in months]
SST_D47_HadCM_old_4PIC_columns_monthly = [f"{month}_SST_D47" for month in months]
d18Oc_HadCM_old_4PIC_columns_monthly = [f"{month}_d18Oc" for month in months]
precip_HadCM_old_4PIC_columns_monthly = [f"{month}_precip" for month in months]

# Combine the relevant columns into a single dataframe
combined_data_HadCM_old_4PIC_monthly = Lutetian_HadCM_old_4PIC_model[SAT_D47_HadCM_old_4PIC_columns_monthly + SST_D47_HadCM_old_4PIC_columns_monthly + d18Oc_HadCM_old_4PIC_columns_monthly + precip_HadCM_old_4PIC_columns_monthly]

# Calculate the covariance matrix for the combined data
cov_combined_HadCM_old_4PIC_monthly = np.cov(combined_data_HadCM_old_4PIC_monthly.dropna(), rowvar=False)

# Extract the covariance matrices for SAT D47, SST D47, d18Oc, and precipitation
cov_HadCM_old_4PIC_SAT_D47_monthly = cov_combined_HadCM_old_4PIC_monthly[:len(months), :len(months)]
cov_HadCM_old_4PIC_SST_D47_monthly = cov_combined_HadCM_old_4PIC_monthly[len(months):2*len(months), len(months):2*len(months)]
cov_HadCM_old_4PIC_d18Oc_monthly = cov_combined_HadCM_old_4PIC_monthly[2*len(months):3*len(months), 2*len(months):3*len(months)]
cov_HadCM_old_4PIC_precip_monthly = cov_combined_HadCM_old_4PIC_monthly[3*len(months):, 3*len(months):]

# Extract the cross-covariance matrices
cross_cov_HadCM_old_4PIC_SAT_SST_D47_monthly = cov_combined_HadCM_old_4PIC_monthly[:len(months), len(months):2*len(months)]
cross_cov_HadCM_old_4PIC_SAT_d18Oc_monthly = cov_combined_HadCM_old_4PIC_monthly[:len(months), 2*len(months):3*len(months)]
cross_cov_HadCM_old_4PIC_SAT_precip_monthly = cov_combined_HadCM_old_4PIC_monthly[:len(months), 3*len(months):]
cross_cov_HadCM_old_4PIC_SST_d18Oc_monthly = cov_combined_HadCM_old_4PIC_monthly[len(months):2*len(months), 2*len(months):3*len(months)]
cross_cov_HadCM_old_4PIC_SST_precip_monthly = cov_combined_HadCM_old_4PIC_monthly[len(months):2*len(months), 3*len(months):]
cross_cov_HadCM_old_4PIC_d18Oc_precip_monthly = cov_combined_HadCM_old_4PIC_monthly[2*len(months):3*len(months), 3*len(months):]

# Normalize each submatrix
normalized_cov_HadCM_old_4PIC_SAT_D47_monthly = normalize_matrix(cov_HadCM_old_4PIC_SAT_D47_monthly)
normalized_cov_HadCM_old_4PIC_SST_D47_monthly = normalize_matrix(cov_HadCM_old_4PIC_SST_D47_monthly)
normalized_cov_HadCM_old_4PIC_d18Oc_monthly = normalize_matrix(cov_HadCM_old_4PIC_d18Oc_monthly)
normalized_cov_HadCM_old_4PIC_precip_monthly = normalize_matrix(cov_HadCM_old_4PIC_precip_monthly)

# Normalize each cross-covariance matrix
normalized_cross_cov_HadCM_old_4PIC_SAT_SST_D47_monthly = normalize_matrix(cross_cov_HadCM_old_4PIC_SAT_SST_D47_monthly)
normalized_cross_cov_HadCM_old_4PIC_SAT_d18Oc_monthly = normalize_matrix(cross_cov_HadCM_old_4PIC_SAT_d18Oc_monthly)
normalized_cross_cov_HadCM_old_4PIC_SAT_precip_monthly = normalize_matrix(cross_cov_HadCM_old_4PIC_SAT_precip_monthly)
normalized_cross_cov_HadCM_old_4PIC_SST_d18Oc_monthly = normalize_matrix(cross_cov_HadCM_old_4PIC_SST_d18Oc_monthly)
normalized_cross_cov_HadCM_old_4PIC_SST_precip_monthly = normalize_matrix(cross_cov_HadCM_old_4PIC_SST_precip_monthly)
normalized_cross_cov_HadCM_old_4PIC_d18Oc_precip_monthly = normalize_matrix(cross_cov_HadCM_old_4PIC_d18Oc_precip_monthly)

# Combine the normalized submatrices into a single normalized covariance matrix
normalized_cov_combined_HadCM_old_4PIC_monthly = np.block([
    [normalized_cov_HadCM_old_4PIC_SAT_D47_monthly, normalized_cross_cov_HadCM_old_4PIC_SAT_SST_D47_monthly, normalized_cross_cov_HadCM_old_4PIC_SAT_d18Oc_monthly, normalized_cross_cov_HadCM_old_4PIC_SAT_precip_monthly],
    [normalized_cross_cov_HadCM_old_4PIC_SAT_SST_D47_monthly.T, normalized_cov_HadCM_old_4PIC_SST_D47_monthly, normalized_cross_cov_HadCM_old_4PIC_SST_d18Oc_monthly, normalized_cross_cov_HadCM_old_4PIC_SST_precip_monthly],
    [normalized_cross_cov_HadCM_old_4PIC_SAT_d18Oc_monthly.T, normalized_cross_cov_HadCM_old_4PIC_SST_d18Oc_monthly.T, normalized_cov_HadCM_old_4PIC_d18Oc_monthly, normalized_cross_cov_HadCM_old_4PIC_d18Oc_precip_monthly],
    [normalized_cross_cov_HadCM_old_4PIC_SAT_precip_monthly.T, normalized_cross_cov_HadCM_old_4PIC_SST_precip_monthly.T, normalized_cross_cov_HadCM_old_4PIC_d18Oc_precip_monthly.T, normalized_cov_HadCM_old_4PIC_precip_monthly]
])

# Plot the heatmap of the normalized combined covariance matrix
plt.figure(figsize=(12, 10))
sns.heatmap(
    normalized_cov_combined_HadCM_old_4PIC_monthly,
    annot=False,
    fmt=".2f",
    cmap="coolwarm",
    center=0,
    xticklabels=SAT_D47_HadCM_old_4PIC_columns_monthly + SST_D47_HadCM_old_4PIC_columns_monthly + d18Oc_HadCM_old_4PIC_columns_monthly + precip_HadCM_old_4PIC_columns_monthly,
    yticklabels=SAT_D47_HadCM_old_4PIC_columns_monthly + SST_D47_HadCM_old_4PIC_columns_monthly + d18Oc_HadCM_old_4PIC_columns_monthly + precip_HadCM_old_4PIC_columns_monthly
)

# Add titles to the axes per parameter
plt.axvline(x=len(SAT_D47_HadCM_old_4PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_HadCM_old_4PIC_columns_monthly) + len(SST_D47_HadCM_old_4PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_HadCM_old_4PIC_columns_monthly) + len(SST_D47_HadCM_old_4PIC_columns_monthly) + len(d18Oc_HadCM_old_4PIC_columns_monthly), color='black', linestyle='--', linewidth=1)

plt.axhline(y=len(SAT_D47_HadCM_old_4PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_HadCM_old_4PIC_columns_monthly) + len(SST_D47_HadCM_old_4PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_HadCM_old_4PIC_columns_monthly) + len(SST_D47_HadCM_old_4PIC_columns_monthly) + len(d18Oc_HadCM_old_4PIC_columns_monthly), color='black', linestyle='--', linewidth=1)

# Add parameter labels
plt.text(len(SAT_D47_HadCM_old_4PIC_columns_monthly) / 2, -2, 'D47 value from SAT', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_old_4PIC_columns_monthly) + len(SST_D47_HadCM_old_4PIC_columns_monthly) / 2, -2, 'D47 value from SST', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_old_4PIC_columns_monthly) + len(SST_D47_HadCM_old_4PIC_columns_monthly) + len(d18Oc_HadCM_old_4PIC_columns_monthly) / 2, -2, 'd18Oc', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_old_4PIC_columns_monthly) + len(SST_D47_HadCM_old_4PIC_columns_monthly) + len(d18Oc_HadCM_old_4PIC_columns_monthly) + len(precip_HadCM_old_4PIC_columns_monthly) / 2, -2, 'Precipitation', ha='center', va='center', fontsize=10)

plt.text(-7, len(SAT_D47_HadCM_old_4PIC_columns_monthly) / 2, 'D47 value from SAT', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-7, len(SAT_D47_HadCM_old_4PIC_columns_monthly) + len(SST_D47_HadCM_old_4PIC_columns_monthly) / 2, 'D47 value from SST', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-7, len(SAT_D47_HadCM_old_4PIC_columns_monthly) + len(SST_D47_HadCM_old_4PIC_columns_monthly) + len(d18Oc_HadCM_old_4PIC_columns_monthly) / 2, 'd18Oc', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-7, len(SAT_D47_HadCM_old_4PIC_columns_monthly) + len(SST_D47_HadCM_old_4PIC_columns_monthly) + len(d18Oc_HadCM_old_4PIC_columns_monthly) + len(precip_HadCM_old_4PIC_columns_monthly) / 2, 'Precipitation', ha='center', va='center', rotation=90, fontsize=10)

plt.title("Normalized Combined Covariance Matrix (HadCM (new) 1x preindustrial pCO2)")
plt.show()
No description has been provided for this image

Test the difference between 2x and 4x preindustrial pCO2¶

In [54]:
# Calculate the difference between the two normalized covariance matrices
normalized_cov_combined_2_4_PIC_diff_monthly = normalized_cov_combined_CESM_2PIC_monthly - normalized_cov_combined_CESM_4PIC_monthly

# Plot the heatmap of the normalized combined covariance matrix
plt.figure(figsize=(12, 10))
sns.heatmap(
    normalized_cov_combined_2_4_PIC_diff_monthly,
    annot=False,
    fmt=".2f",
    cmap="coolwarm",
    center=0,
    xticklabels=SAT_D47_CESM_2PIC_columns_monthly + SST_D47_CESM_2PIC_columns_monthly + d18Oc_CESM_2PIC_columns_monthly + precip_CESM_2PIC_columns_monthly,
    yticklabels=SAT_D47_CESM_2PIC_columns_monthly + SST_D47_CESM_2PIC_columns_monthly + d18Oc_CESM_2PIC_columns_monthly + precip_CESM_2PIC_columns_monthly
)

# Add titles to the axes per parameter
plt.axvline(x=len(SAT_D47_CESM_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly) + len(d18Oc_CESM_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)

plt.axhline(y=len(SAT_D47_CESM_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly) + len(d18Oc_CESM_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)

# Add parameter labels
plt.text(len(SAT_D47_CESM_2PIC_columns_monthly) / 2, -2, 'D47 value from SAT', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly) / 2, -2, 'D47 value from SST', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly) + len(d18Oc_CESM_2PIC_columns_monthly) / 2, -2, 'd18Oc', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly) + len(d18Oc_CESM_2PIC_columns_monthly) + len(precip_CESM_2PIC_columns_monthly) / 2, -2, 'Precipitation', ha='center', va='center', fontsize=10)

plt.text(-7, len(SAT_D47_CESM_2PIC_columns_monthly) / 2, 'D47 value from SAT', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-7, len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly) / 2, 'D47 value from SST', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-7, len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly) + len(d18Oc_CESM_2PIC_columns_monthly) / 2, 'd18Oc', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-7, len(SAT_D47_CESM_2PIC_columns_monthly) + len(SST_D47_CESM_2PIC_columns_monthly) + len(d18Oc_CESM_2PIC_columns_monthly) + len(precip_CESM_2PIC_columns_monthly) / 2, 'Precipitation', ha='center', va='center', rotation=90, fontsize=10)

plt.title("Normalized difference between covariance Matrices (CESM 2x - 4x preindustrial pCO2)")
plt.show()
No description has been provided for this image

Test the difference between old and new HadCM model at 2x preindustrial pCO2¶

In [55]:
# Calculate the difference between the two normalized covariance matrices
normalized_cov_combined_HadCM_old_new_PIC_diff_monthly = normalized_cov_combined_HadCM_old_2PIC_monthly - normalized_cov_combined_HadCM_new_2PIC_monthly

# Plot the heatmap of the normalized combined covariance matrix
plt.figure(figsize=(12, 10))
sns.heatmap(
    normalized_cov_combined_HadCM_old_new_PIC_diff_monthly,
    annot=False,
    fmt=".2f",
    cmap="coolwarm",
    center=0,
    xticklabels=SAT_D47_HadCM_old_2PIC_columns_monthly + SST_D47_HadCM_old_2PIC_columns_monthly + d18Oc_HadCM_old_2PIC_columns_monthly + precip_HadCM_old_2PIC_columns_monthly,
    yticklabels=SAT_D47_HadCM_old_2PIC_columns_monthly + SST_D47_HadCM_old_2PIC_columns_monthly + d18Oc_HadCM_old_2PIC_columns_monthly + precip_HadCM_old_2PIC_columns_monthly
)

# Add titles to the axes per parameter
plt.axvline(x=len(SAT_D47_HadCM_old_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axvline(x=len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly) + len(d18Oc_HadCM_old_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)

plt.axhline(y=len(SAT_D47_HadCM_old_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)
plt.axhline(y=len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly) + len(d18Oc_HadCM_old_2PIC_columns_monthly), color='black', linestyle='--', linewidth=1)

# Add parameter labels
plt.text(len(SAT_D47_HadCM_old_2PIC_columns_monthly) / 2, -2, 'D47 value from SAT', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly) / 2, -2, 'D47 value from SST', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly) + len(d18Oc_HadCM_old_2PIC_columns_monthly) / 2, -2, 'd18Oc', ha='center', va='center', fontsize=10)
plt.text(len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly) + len(d18Oc_HadCM_old_2PIC_columns_monthly) + len(precip_HadCM_old_2PIC_columns_monthly) / 2, -2, 'Precipitation', ha='center', va='center', fontsize=10)

plt.text(-7, len(SAT_D47_HadCM_old_2PIC_columns_monthly) / 2, 'D47 value from SAT', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-7, len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly) / 2, 'D47 value from SST', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-7, len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly) + len(d18Oc_HadCM_old_2PIC_columns_monthly) / 2, 'd18Oc', ha='center', va='center', rotation=90, fontsize=10)
plt.text(-7, len(SAT_D47_HadCM_old_2PIC_columns_monthly) + len(SST_D47_HadCM_old_2PIC_columns_monthly) + len(d18Oc_HadCM_old_2PIC_columns_monthly) + len(precip_HadCM_old_2PIC_columns_monthly) / 2, 'Precipitation', ha='center', va='center', rotation=90, fontsize=10)

plt.title("Normalized difference between covariance Matrices (CESM 2x - 4x preindustrial pCO2)")
plt.show()
No description has been provided for this image

Create combined monthly state vector¶

In [56]:
# Combine the prior means of D47 and SAT into a single state vector
mu_prior_CESM_4PIC_monthly_combined = np.concatenate((mu_prior_CESM_4PIC_SST_D47_monthly, mu_prior_CESM_4PIC_SAT_D47_monthly, mu_prior_CESM_4PIC_d18Oc_monthly, mu_prior_CESM_4PIC_precip_monthly))
mu_prior_CESM_2PIC_monthly_combined = np.concatenate((mu_prior_CESM_2PIC_SST_D47_monthly, mu_prior_CESM_2PIC_SAT_D47_monthly, mu_prior_CESM_2PIC_d18Oc_monthly, mu_prior_CESM_2PIC_precip_monthly))
mu_prior_HadCM_new_1PIC_monthly_combined = np.concatenate((mu_prior_HadCM_new_1PIC_SST_D47_monthly, mu_prior_HadCM_new_1PIC_SAT_D47_monthly, mu_prior_HadCM_new_1PIC_d18Oc_monthly, mu_prior_HadCM_new_1PIC_precip_monthly))
mu_prior_HadCM_new_2PIC_monthly_combined = np.concatenate((mu_prior_HadCM_new_2PIC_SST_D47_monthly, mu_prior_HadCM_new_2PIC_SAT_D47_monthly, mu_prior_HadCM_new_2PIC_d18Oc_monthly, mu_prior_HadCM_new_2PIC_precip_monthly))
mu_prior_HadCM_new_1056ppm_monthly_combined = np.concatenate((mu_prior_HadCM_new_1056ppm_SST_D47_monthly, mu_prior_HadCM_new_1056ppm_SAT_D47_monthly, mu_prior_HadCM_new_1056ppm_d18Oc_monthly, mu_prior_HadCM_new_1056ppm_precip_monthly))
mu_prior_HadCM_old_2PIC_monthly_combined = np.concatenate((mu_prior_HadCM_old_2PIC_SST_D47_monthly, mu_prior_HadCM_old_2PIC_SAT_D47_monthly, mu_prior_HadCM_old_2PIC_d18Oc_monthly, mu_prior_HadCM_old_2PIC_precip_monthly))
mu_prior_HadCM_old_4PIC_monthly_combined = np.concatenate((mu_prior_HadCM_old_4PIC_SST_D47_monthly, mu_prior_HadCM_old_4PIC_SAT_D47_monthly, mu_prior_HadCM_old_4PIC_d18Oc_monthly, mu_prior_HadCM_old_4PIC_precip_monthly))


# Combine the covariance matrices of D47 values of SST and SAT, including the cross-covariance
cov_prior_CESM_4PIC_monthly_combined = cov_combined_CESM_4PIC_monthly.copy()
cov_prior_CESM_2PIC_monthly_combined = cov_combined_CESM_2PIC_monthly.copy()
cov_prior_HadCM_new_1PIC_monthly_combined = cov_combined_HadCM_new_1PIC_monthly.copy()
cov_prior_HadCM_new_2PIC_monthly_combined = cov_combined_HadCM_new_2PIC_monthly.copy()
cov_prior_HadCM_new_1056ppm_monthly_combined = cov_combined_HadCM_new_1056ppm_monthly.copy()
cov_prior_HadCM_old_2PIC_monthly_combined = cov_combined_HadCM_old_2PIC_monthly.copy()
cov_prior_HadCM_old_4PIC_monthly_combined = cov_combined_HadCM_old_4PIC_monthly.copy()

OBSERVATIONS¶

Load clumped data for updating¶

Monthly data from Paris Basin Campanile giganteum paper (Van Horebeek et al. 2025)¶

In [57]:
# Load seasonal measurements and format them into a dictionary
# This is precompiled seasonal data per specimen and therefore does not come with a time uncertainty
Lutetian_seasonally_aggregated_data = pd.read_csv('Lutetian case/D47_season_data_calc.csv') # Load the data for seasonal averages
Lutetian_seasonally_aggregated_data_dict = Lutetian_seasonally_aggregated_data.to_dict('records') # Convert to dictionary with column headers as keys

# Add an entry for the time uncertainty (which is always zero in this case, because data is already aggregated monthly)
for record in Lutetian_seasonally_aggregated_data_dict:
    record["Season_err"] = 0 # Set the time uncertainty to zero
    record["D47_se"] = record["D47_SD"] / np.sqrt(record["count"]) # Calculate the standard error of the D47 value

print(Lutetian_seasonally_aggregated_data_dict[0]) # Print to check the structure of the data
{'Season': 'summer', 'Whorl...P.or.T': 'AW', 'X': 'AX', 'D47_mean': 0.589860492, 'D47_SD': 0.042653301, 'count': 62, 'd18O': -2.150527044, 'd18O_SD': 0.312787802, 'T': 27.892776, 'CL95': 0.010920335, 'CL95_T': 3.824099323, 'd18Osw': -0.27016391, 'DOY': 203.6572, 'Tmin': 24.20918351, 'Tmax': 31.71674359, 'dwmin': -1.11891794, 'dwmax': 0.610934613, 'Season_err': 0, 'D47_se': 0.005416974643977352}

Raw data at the sample level¶

In [58]:
# Load measurements and format them into a dictionary
# These are the actual individual D47 and d18Oc measurements and ShellChron outcomes and thus come with a time uncertainty which can be propagated.
Lutetian_D47_data = pd.read_csv('Lutetian case/Campanile_sample_data_calc2.csv') # Load data for individual D47 and d18Oc measurements and ShellChron outcomes
Lutetian_data_dict = Lutetian_D47_data.to_dict('records') # Convert to dictionary with column headers as keys

# Add an entry for the time uncertainty (which is always zero in this case, because there is no time uncertainty in the raw data)
for record in Lutetian_data_dict:
    # Handle missing values and convert from days to months and seasons
    shell_chron_doy_err = record.get("DOY_SD", np.nan)  # Get value, default to NaN if missing
    if pd.isna(shell_chron_doy_err):  # Check if the value is NaN
        record["Month_err"] = 0 # Set the time uncertainty to zero
        record["Season_err"] = 0 # Set the time uncertainty to zero
        record["no_err"] = 0 # Set the time uncertainty to zero
    else:
        record["Month_err"] = shell_chron_doy_err / 365 * 12  # Convert days to months
        record["Season_err"] = shell_chron_doy_err / 365 * 4 # Convert days to seasons
        record["no_err"] = 0 # Set the time uncertainty to zero for no error
    # Assign the D47 value and its standard deviation
    record["D47_SD"] = 0.029 # Assign external standard deviation to the D47 value (based on reproducibility of IAEA-C2 measurements)
    record["season_score"] = np.floor(((record["DOY"] + 45) % 365) / 365 * 4) # Calculate the season score from DOY value (winter = 0, spring = 1, summer = 2, autumn = 3). Shift two months to align with the seasons defined in paper.
    record["month_score"] = np.floor(((record["DOY"]) % 365) / 365 * 12) # Calculate the month score from DOY value (January = 0, February = 1, ..., December = 11).

print(Lutetian_data_dict[0]) # Print to check the structure of the data
{'ID': 'AB002', 'D': 5.0, 'Run': nan, 'Row': nan, 'Sample.intensity': nan, 'X49.parameter': nan, 'D47_raw': nan, 'D47_SD': 0.029, 'D47_final': nan, 'Temperature': nan, 'd18O': -1.5, 'd13C': 2.15, 'Whorl': nan, 'sample_nr': nan, 'Year': nan, 'season_manual': nan, 'd18O_SD': 0.1, 'day': 145.316271, 'DOY_SD': nan, 'season_label': nan, 'T_d18O': nan, 'DOY': 145.316271, 'Season': nan, 'Month_err': 0, 'Season_err': 0, 'no_err': 0, 'season_score': 2.0, 'month_score': 4.0}

Aggregate proxy data to monthly bins¶

In [59]:
# Aggregate and summarize proxy data per month, tracking mean and propagated SE for D47 and d18O separately
monthly_agg = []
for month in range(12):
    month_records = [record for record in Lutetian_data_dict if int(record["month_score"]) == month]
    entry = {
        "month_score": month,
        "D47_mean": np.nanmean([rec.get("D47_final") for rec in month_records if not pd.isna(rec.get("D47_final"))]),
        "D47_SD": np.sqrt(np.nansum([rec.get("D47_SD", np.nan) ** 2 for rec in month_records if not pd.isna(rec.get("D47_SD")) and not pd.isna(rec.get("D47_final"))])) / max(1, len([rec for rec in month_records if not pd.isna(rec.get("D47_SD")) and not pd.isna(rec.get("D47_final"))])),
        "d18O": np.nanmean([rec.get("d18O") for rec in month_records if not pd.isna(rec.get("d18O"))]),
        "d18O_SD": np.sqrt(np.nansum([rec.get("d18O_SD", np.nan) ** 2 for rec in month_records if not pd.isna(rec.get("d18O_SD")) and not pd.isna(rec.get("d18O"))])) / max(1, len([rec for rec in month_records if not pd.isna(rec.get("d18O_SD")) and not pd.isna(rec.get("d18O"))])),
        "Month_err": 0
    }
    monthly_agg.append(entry)
Lutetian_data_monthly_aggregated_df = pd.DataFrame(monthly_agg)
Lutetian_data_monthly_aggregated_dict = Lutetian_data_monthly_aggregated_df.to_dict("records")

print(Lutetian_data_monthly_aggregated_dict[0]) # Print to check the structure of the data
print(Lutetian_data_monthly_aggregated_dict[0]) # Print to check the structure of the data
{'month_score': 0, 'D47_mean': 0.6315000000000001, 'D47_SD': 0.0145, 'd18O': 0.016000000000000014, 'd18O_SD': 0.0447213595499958, 'Month_err': 0}
{'month_score': 0, 'D47_mean': 0.6315000000000001, 'D47_SD': 0.0145, 'd18O': 0.016000000000000014, 'd18O_SD': 0.0447213595499958, 'Month_err': 0}
C:\Users\nwi213\AppData\Local\Temp\ipykernel_4724\1428035188.py:7: RuntimeWarning: Mean of empty slice
  "D47_mean": np.nanmean([rec.get("D47_final") for rec in month_records if not pd.isna(rec.get("D47_final"))]),

Prepare measurement and observation matrices¶

Define a wrapped normal distribution to allow uncertainty in the time domain to flow around the year¶

In [60]:
# Function to calculate wrapped normal distribution weights
def wrapped_normal_pdf(x, mean, sd, num_bins):
    # Calculate the normal PDF for each bin
    pdf = stats.norm.pdf(x, loc = mean, scale = sd)
    # Wrap around the bins
    for i in range(1, num_bins):
        pdf += stats.norm.pdf(x + i * num_bins, loc = mean, scale = sd)
        pdf += stats.norm.pdf(x - i * num_bins, loc = mean, scale = sd)
    # Normalize the weights to ensure the sum equals 1
    pdf /= pdf.sum()
    return pdf

Observations aggregated by season¶

Measurement matrix for monthly-averaged D47 and d18Oc values¶

In [61]:
# Extract measurements and uncertainties from the dictionary
D47_measurements = [measurement["D47_mean"] for measurement in Lutetian_data_monthly_aggregated_dict] # Extract the D47 values from monthly aggregated data
d18Oc_measurements = [measurement["d18O"] for measurement in Lutetian_data_monthly_aggregated_dict] # Extract the d18Oc values from monthly aggregated data
D47_measurements_se = [measurement["D47_SD"] ** 2 for measurement in Lutetian_data_monthly_aggregated_dict] # Square the standard deviation to get the variance
d18Oc_measurements_se = [measurement["d18O_SD"] ** 2 for measurement in Lutetian_data_monthly_aggregated_dict] # Square the standard deviation to get the variance

# OPTIONAL: Lower boundary d18Oc variance at 0.01 (equivalent to 0.1 per mil measurement uncertainty)
d18Oc_measurements_se = [max(uncertainty, 0.01) for uncertainty in d18Oc_measurements_se]  # Ensure the uncertainty variance is at least 0.01

# Create the measurement matrix Z
Z = np.array(D47_measurements + d18Oc_measurements).reshape(-1, 1) # Combine D47 and d18Oc measurements into a single matrix

# Create the measurement uncertainty matrix R (diagonal matrix)
R = np.diag(D47_measurements_se + d18Oc_measurements_se) # Combine the variances of D47 and d18Oc measurements into a single diagonal matrix

# Number of seasonally averaged measurements
N_measurements = len(Z) # Get the number of aggregated measurements

Observation matrix for season- and monthly-averaged D47 and d18Oc data from seasonally aggregated proxy measurements¶

In [62]:
# Create the observation matrix H for seasonal data based on seasonally aggregated data
H = np.zeros((N_measurements, len(mu_prior_CESM_4PIC_monthly_combined)))

# Fill the monthly observation matrix H with ones at the positions corresponding to the measurements
half_monthly = int(N_measurements / 2)
for i, measurement in enumerate(Lutetian_data_monthly_aggregated_dict):
    month_index = int(measurement["month_score"])
    # First half: D47 (SST)
    H[i, month_index] = 1
    # Second half: d18Oc (SSS)
    H[i + half_monthly, month_index + 24] = 1

print(H)
[[1. 0. 0. ... 0. 0. 0.]
 [0. 1. 0. ... 0. 0. 0.]
 [0. 0. 1. ... 0. 0. 0.]
 ...
 [0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]]

DEFINE UPDATING FUNCTIONS¶

Create updating function (Kalman filter)¶

  • Include updating of second variable (SAT) through cross-covariance
  • Use block updating

Input:

  • Prior means (mu_prior)
  • Prior covariance matrix (P)
  • Observation matrix (H)
  • Measurement matrix (Z)
  • Uncertainty matrix (R)

Output:

  • Posterior means (mu_post)
  • Posterior covariance matrix (P_post)
In [63]:
def kalman_update_block(
    mu_prior: np.ndarray,
    cov_prior: np.ndarray,
    Z: np.ndarray,
    R: np.ndarray,
    H: np.ndarray,
    debug_print: bool = False
):
    """
    Perform a Kalman update step for a block of observations.

    Parameters:
    mu_prior (np.ndarray): The prior mean vector.
    cov_prior (np.ndarray): The prior covariance matrix.
    Z (np.ndarray): The measurement matrix.
    R (np.ndarray): The measurement noise covariance matrix.
    H (np.ndarray): The observation matrix.
    debug_print (bool): If True, print debug statements.

    Returns:
    mu_posterior (np.ndarray): The posterior mean vector.
    cov_posterior (np.ndarray): The posterior covariance matrix.
    """
    if debug_print:
        # Print shapes of key variables for debugging
        print("Shape of cov_prior:", cov_prior.shape)
        print("Shape of H:", H.shape)
        print("Shape of R:", R.shape)
        print("Shape of mu_prior:", mu_prior.shape)
        print("Shape of Z:", Z.shape)

    # Compute the Kalman gain
    K = cov_prior @ H.T @ np.linalg.inv(H @ cov_prior @ H.T + R)
    if debug_print:
        print("K matrix:", K)
        print("Shape of K:", K.shape)

    # In-between steps for debugging
    Y_hat = H @ mu_prior  # Compute the predicted observation
    if debug_print:
        print("Y_hat:", Y_hat)
        print("Shape of Y_hat:", Y_hat.shape)
    innovation = Z - Y_hat.reshape(-1, 1)  # Compute the innovation
    if debug_print:
        print("Innovation:", innovation)
        print("Shape of innovation:", innovation.shape)
    # Replace NaN values in innovation with zeros
    innovation = np.nan_to_num(innovation, nan=0.0)
    kalman_gain = (K @ innovation).flatten()
    if debug_print:
        print("Kalman gain:", kalman_gain)
        print("Shape of kalman_gain:", kalman_gain.shape)

    # Update the posterior mean estimate
    mu_posterior = mu_prior + kalman_gain.flatten()

    # Update the posterior covariance estimate
    cov_posterior = cov_prior - K @ H @ cov_prior

    return mu_posterior, cov_posterior

Create function to track the statistics of the likelihood (combining just the reconstruction data)¶

In [64]:
# UPDATED SCRIPT TO ACCOMMODATE MULTIPLE VARIABLES
# Create function to keep track of the likelihood statistics and data

def likelihood_statistics_multi(
    weighted_sum,
    effective_weights_total,
    n_update,
    data_library,
    measurement,
    timestamp,
    timestamp_sd,
    Variable_names = ["Variable_name1", "Variable_name2"],
    Variable_names_SDs = ["Variable_name_SD1", "Variable_name_SD2"]
):
    """
    Incrementally updates the likelihood statistics for seasonal data.

    Parameters:
    - weighted_sum: list
        List tracking the mean times the effective weight for each time bin and variable.
    - effective_weights_total: list
        List tracking the sum of effective weights for each time bin and variable.
    - n_update: list
        List tracking the number of datapoints for each time bin and variable.
    - data_library: dict
        Dictionary tracking individual data points and their uncertainties.
    - measurement: dict
        A single measurement containing data on multiple variables.
    - timestamp: str
        Key in the measurement dictionary for the timestamp (0-based index).
    - timestamp_sd: float
        Standard deviation of uncertainty in the timestamp.
    - Variable_name: list of str
        Key in the measurement dictionary for the variables (e.g. d18Os, D47).
    - Variable_name_SD: list of str
        Key in the measurement dictionary for the standard deviation on the variables (e.g. d18Os, D47).
    """
    # Check if at least one combination of variable name and its SD is present in the measurement
    found = False
    for var_name, var_sd_name in zip(Variable_names, Variable_names_SDs):
        if var_name in measurement and var_sd_name in measurement:
            found = True
            break

    if timestamp in measurement and found:
        # Extract the time and data values from the measurement
        time = measurement[timestamp]
        time_sd = measurement[timestamp_sd]
        # Loop through all variable/SD pairs
        for var_name, var_sd_name in zip(Variable_names, Variable_names_SDs):
            if var_name in measurement and var_sd_name in measurement:
                data_val = measurement[var_name]
                data_sd = measurement[var_sd_name]
                
                # Check if the data is valid
                if not np.isnan(data_val) and not np.isnan(data_sd):
                    # Calculate the weight (inverse of variance)
                    weight = 1 / (data_sd ** 2)

                    # Determine the number of bins
                    num_bins_seasonal = int(len(weighted_sum) / len(Variable_names))
                    # Ensure num_bins_seasonal is an integer
                    bin_indices = np.arange(num_bins_seasonal, dtype=np.float64)

                    # Calculate the probability density for each bin
                    if time_sd == 0:  # Catch cases where the time uncertainty is zero (or unknown)
                        probabilities = np.zeros(num_bins_seasonal, dtype=np.float64)
                        bin_index = int(time) % num_bins_seasonal  # Ensure the bin index is within range
                        probabilities[bin_index] = 1  # Set the probability to 1 for the correct bin
                    else:
                        probabilities = stats.norm.pdf(bin_indices, loc=time, scale=time_sd)  # For non-zero time uncertainty, use a normal distribution
                        probabilities /= probabilities.sum()  # Normalize to ensure the sum of probabilities is 1

                    for i, prob in enumerate(probabilities):  # Loop over all possible bin numbers in the probability vector
                        bin_index = i % num_bins_seasonal  # Wrap around to the first bin if it overflows

                        # Update the weighted sums and sample count
                        effective_weight = weight * prob
                        var_idx = Variable_names.index(var_name)  # Find the index of the variable
                        idx = int(var_idx * num_bins_seasonal + bin_index)  # Unique index for (variable, bin)
                        if weighted_sum[idx] is None:
                            weighted_sum[idx] = 0
                            effective_weights_total[idx] = 0
                        weighted_sum[idx] = weighted_sum[idx] + data_val * effective_weight
                        effective_weights_total[idx] = effective_weights_total[idx] + effective_weight

                    # Update n_update for the correct variable and bin
                    var_idx = Variable_names.index(var_name) # Find the index of the variable
                    n_update[var_idx * num_bins_seasonal + (int(time) % num_bins_seasonal)] += 1  # update sample number per bin and variable

                    # Track individual data points and their uncertainties
                    key = (var_name, int(time)) # Store individual data points in a dictionary with (variable, time) as key
                    if key not in data_library:
                        data_library[key] = []  # Initialize the list for a new (time, var_name) pair
                    data_library[key].append((time_sd, data_val, data_sd))
    return weighted_sum, effective_weights_total, n_update, data_library # Return the updated values

EXECUTE UPDATING FUNCTIONS - MONTHLY¶

Update monthly priors from CESM 4x preindustrial pCO2 with aggregated data¶

  • Data and model outcomes aggregated in 12 months
  • No sclero-dating uncertainty
  • D47 Data aggregated per specimen and per month
In [65]:
# Apply Kalman function to update the prior with monthly data including updating the prec estimates
# Update the monthly D47 and prec prior with all measurements using block updating
monthly_aggregated_data = {} # Keep track of datapoints per season
n_update_CESM_4PIC = np.concatenate([mu_prior_CESM_4PIC_SST_D47_monthly * 0, mu_prior_CESM_4PIC_d18Oc_monthly * 0]) # Vector to store sample size per season for confidence interval plotting
weighted_sum_CESM_4PIC = np.concatenate([mu_prior_CESM_4PIC_SST_D47_monthly * 0, mu_prior_CESM_4PIC_d18Oc_monthly * 0]) # Vector to store mean temperature per season for confidence interval plotting
effective_weights_total_CESM_4PIC = np.concatenate([mu_prior_CESM_4PIC_SST_D47_monthly * 0, mu_prior_CESM_4PIC_d18Oc_monthly * 0]) # Vector to store temperature uncertainty per season for confidence interval plotting
mu_likelihood = np.concatenate([mu_prior_CESM_4PIC_SST_D47_monthly * 0, mu_prior_CESM_4PIC_d18Oc_monthly * 0]) # Vector to store mean temperature per season for confidence interval plotting
std_likelihood = np.concatenate([mu_prior_CESM_4PIC_SST_D47_monthly * 0, mu_prior_CESM_4PIC_d18Oc_monthly * 0]) # Vector to store temperature uncertainty per season for confidence interval plotting
var_names = ["D47_mean", "d18O"] # List of variable names which are updated
var_SD_names = ["D47_SD", "d18O_SD"] # List of names of variable uncertainties which are updated

# Update the prior with monthly data using the Kalman filter in block updating form
mu_post_CESM_4PIC, cov_post_CESM_4PIC = kalman_update_block(
    mu_prior_CESM_4PIC_monthly_combined,
    cov_prior_CESM_4PIC_monthly_combined,
    Z,
    R,
    H
)

# Extract the updated mean values from the combined state vector
mu_post_CESM_4PIC_SST_D47 = mu_post_CESM_4PIC[:len(mu_prior_CESM_4PIC_SST_D47_monthly)]
mu_post_CESM_4PIC_SAT_D47 = mu_post_CESM_4PIC[len(mu_prior_CESM_4PIC_SST_D47_monthly):2*len(mu_prior_CESM_4PIC_SST_D47_monthly)]
mu_post_CESM_4PIC_d18Oc = mu_post_CESM_4PIC[2*len(mu_prior_CESM_4PIC_SST_D47_monthly):3*len(mu_prior_CESM_4PIC_SST_D47_monthly)]
mu_post_CESM_4PIC_precip = mu_post_CESM_4PIC[3*len(mu_prior_CESM_4PIC_d18Oc_monthly):]

# Extract the updated covariance matrices from the combined covariance matrix
cov_post_CESM_4PIC_SST_D47 = cov_post_CESM_4PIC[:len(mu_prior_CESM_4PIC_SST_D47_monthly), :len(mu_prior_CESM_4PIC_SST_D47_monthly)]
cov_post_CESM_4PIC_SAT_D47 = cov_post_CESM_4PIC[len(mu_prior_CESM_4PIC_SST_D47_monthly):2*len(mu_prior_CESM_4PIC_SST_D47_monthly), len(mu_prior_CESM_4PIC_SST_D47_monthly):2*len(mu_prior_CESM_4PIC_SST_D47_monthly)]
cov_post_CESM_4PIC_d18Oc = cov_post_CESM_4PIC[2*len(mu_prior_CESM_4PIC_SST_D47_monthly):3*len(mu_prior_CESM_4PIC_SST_D47_monthly), 2*len(mu_prior_CESM_4PIC_SST_D47_monthly):3*len(mu_prior_CESM_4PIC_SST_D47_monthly)]
cov_post_CESM_4PIC_precip = cov_post_CESM_4PIC[3*len(mu_prior_CESM_4PIC_d18Oc_monthly):, 3*len(mu_prior_CESM_4PIC_d18Oc_monthly):]

for measurement in Lutetian_data_monthly_aggregated_dict: # Loop over measurements    
    # Track and update likelihood statistics
    weighted_sum_CESM_4PIC, effective_weights_total_CESM_4PIC, n_update_CESM_4PIC, monthly_aggregated_data = likelihood_statistics_multi(
        weighted_sum_CESM_4PIC,
        effective_weights_total_CESM_4PIC,
        n_update_CESM_4PIC,
        monthly_aggregated_data,
        measurement,
        timestamp = "month_score",
        timestamp_sd = "Month_err",
        Variable_names = var_names,
        Variable_names_SDs = var_SD_names
    )

# Normalize the weighted_sum_CESM_4PIC to obtain weighted mean
# Calculate inverse square root of the effective_weights_total_CESM_4PIC to contain the weighted standard deviation
# Print likelihood statistics
print("Likelihood statistics:")
num_vars = len(var_names)  # number of variables (e.g., D47, d18O)
num_bins_monthly = int(len(weighted_sum_CESM_4PIC) / num_vars)

for var_idx, var_name in enumerate(var_names):
    print(f"Results for variable: {var_name}")
    for bin_idx in range(num_bins_monthly):
        idx = var_idx * num_bins_monthly + bin_idx
        if effective_weights_total_CESM_4PIC[idx] is not None and effective_weights_total_CESM_4PIC[idx] != 0:
            mu_likelihood[idx] = weighted_sum_CESM_4PIC[idx] / effective_weights_total_CESM_4PIC[idx]
            std_likelihood[idx] = np.sqrt(1 / effective_weights_total_CESM_4PIC[idx])
        else:
            # If there are no data points for this bin, set the likelihood to NaN
            mu_likelihood[idx] = np.nan
            std_likelihood[idx] = np.nan
        print(f"  Bin {bin_idx + 1}:")
        print(f"    Weighted Average: {mu_likelihood[idx]}")
        print(f"    Aggregated Uncertainty: {std_likelihood[idx]}")
        print(f"    Number of Data Points: {n_update_CESM_4PIC[idx]}")
    print()

print("Original Prior Mean SST-D47 monthly:\n", mu_prior_CESM_4PIC_SST_D47_monthly_original)
print("Original Prior Standard Deviation SST-D47 monthly:\n", np.sqrt(np.diag(cov_prior_CESM_4PIC_SST_D47_monthly_original)))
print("Updated Posterior Mean SST-D47 monthly:\n", mu_post_CESM_4PIC_SST_D47)
print("Updated Posterior Standard Deviation SST-D47 monthly:\n", np.sqrt(np.diag(cov_post_CESM_4PIC_SST_D47)))
print("Original Prior Mean SAT-D47 monthly:\n", mu_prior_CESM_4PIC_SAT_monthly_original)
print("Original Prior Standard Deviation SAT-D47 monthly:\n", np.sqrt(np.diag(cov_prior_CESM_4PIC_SAT_monthly_original)))
print("Updated Posterior Mean SAT-D47 monthly:\n", mu_post_CESM_4PIC_SAT_D47)
print("Updated Posterior Standard Deviation SAT-D47 monthly:\n", np.sqrt(np.diag(cov_post_CESM_4PIC_SAT_D47)))
print("Original Prior Mean d18Oc monthly:\n", mu_prior_CESM_4PIC_d18Oc_monthly_original)
print("Original Prior Standard Deviation d18Oc monthly:\n", np.sqrt(np.diag(cov_prior_CESM_4PIC_d18Oc_monthly_original)))
print("Updated Posterior Mean d18Oc monthly:\n", mu_post_CESM_4PIC_d18Oc)
print("Updated Posterior Standard Deviation d18Oc monthly:\n", np.sqrt(np.diag(cov_post_CESM_4PIC_d18Oc)))
print("Original Prior Mean precipitation monthly:\n", mu_prior_CESM_4PIC_precip_monthly_original)
print("Original Prior Standard Deviation precipitation monthly:\n", np.sqrt(np.diag(cov_prior_CESM_4PIC_precip_monthly_original)))
print("Updated Posterior Mean precipitation monthly:\n", mu_post_CESM_4PIC_precip)
print("Updated Posterior Standard Deviation precipitation monthly:\n", np.sqrt(np.diag(cov_post_CESM_4PIC_precip)))
Likelihood statistics:
Results for variable: D47_mean
  Bin 1:
    Weighted Average: 0.6315000000000001
    Aggregated Uncertainty: 0.0145
    Number of Data Points: 1.0
  Bin 2:
    Weighted Average: 0.5964285714285714
    Aggregated Uncertainty: 0.01096096971726759
    Number of Data Points: 1.0
  Bin 3:
    Weighted Average: 0.6065
    Aggregated Uncertainty: 0.010253048327204941
    Number of Data Points: 1.0
  Bin 4:
    Weighted Average: nan
    Aggregated Uncertainty: nan
    Number of Data Points: 0.0
  Bin 5:
    Weighted Average: 0.5749687499999999
    Aggregated Uncertainty: 0.0051265241636024705
    Number of Data Points: 1.0
  Bin 6:
    Weighted Average: 0.5925625
    Aggregated Uncertainty: 0.00725
    Number of Data Points: 1.0
  Bin 7:
    Weighted Average: 0.5888260869565218
    Aggregated Uncertainty: 0.004275816728492018
    Number of Data Points: 1.0
  Bin 8:
    Weighted Average: nan
    Aggregated Uncertainty: nan
    Number of Data Points: 0.0
  Bin 9:
    Weighted Average: 0.5830000000000001
    Aggregated Uncertainty: 0.004973458969132757
    Number of Data Points: 1.0
  Bin 10:
    Weighted Average: nan
    Aggregated Uncertainty: nan
    Number of Data Points: 0.0
  Bin 11:
    Weighted Average: 0.594
    Aggregated Uncertainty: 0.011839200423452026
    Number of Data Points: 1.0
  Bin 12:
    Weighted Average: 0.5921333333333333
    Aggregated Uncertainty: 0.007487767802667672
    Number of Data Points: 1.0

Results for variable: d18O
  Bin 1:
    Weighted Average: 0.016000000000000014
    Aggregated Uncertainty: 0.0447213595499958
    Number of Data Points: 1.0
  Bin 2:
    Weighted Average: 0.10700000000000001
    Aggregated Uncertainty: 0.0316227766016838
    Number of Data Points: 1.0
  Bin 3:
    Weighted Average: -0.22615384615384615
    Aggregated Uncertainty: 0.02773500981126146
    Number of Data Points: 1.0
  Bin 4:
    Weighted Average: -0.5469999999999999
    Aggregated Uncertainty: 0.01414213562373095
    Number of Data Points: 1.0
  Bin 5:
    Weighted Average: -1.2017647058823526
    Aggregated Uncertainty: 0.009166984970282115
    Number of Data Points: 1.0
  Bin 6:
    Weighted Average: -1.6498290598290601
    Aggregated Uncertainty: 0.009245003270420488
    Number of Data Points: 1.0
  Bin 7:
    Weighted Average: -2.0610810810810816
    Aggregated Uncertainty: 0.009491579957524992
    Number of Data Points: 1.0
  Bin 8:
    Weighted Average: -1.7621904761904763
    Aggregated Uncertainty: 0.009759000729485335
    Number of Data Points: 1.0
  Bin 9:
    Weighted Average: -1.3562711864406782
    Aggregated Uncertainty: 0.009205746178983237
    Number of Data Points: 1.0
  Bin 10:
    Weighted Average: -0.5620833333333334
    Aggregated Uncertainty: 0.014433756729740647
    Number of Data Points: 1.0
  Bin 11:
    Weighted Average: -0.06419354838709676
    Aggregated Uncertainty: 0.017960530202677495
    Number of Data Points: 1.0
  Bin 12:
    Weighted Average: -0.162
    Aggregated Uncertainty: 0.0223606797749979
    Number of Data Points: 1.0

Original Prior Mean SST-D47 monthly:
 [0.59656789 0.59858139 0.59867924 0.59638204 0.58858685 0.57705811
 0.56727922 0.56351195 0.5670409  0.57510508 0.58376364 0.59171077]
Original Prior Standard Deviation SST-D47 monthly:
 [0.00890411 0.00944467 0.00936157 0.00859554 0.00739686 0.00653869
 0.00575527 0.00534817 0.00493985 0.00482531 0.00621776 0.00782822]
Updated Posterior Mean SST-D47 monthly:
 [0.59746433 0.59942274 0.59953844 0.59638204 0.5892276  0.57770401
 0.56711071 0.56351195 0.56748139 0.57510508 0.58307085 0.5924027 ]
Updated Posterior Standard Deviation SST-D47 monthly:
 [1.32467442e-03 8.57442039e-04 5.08756743e-04 7.08126758e-10
 9.15449230e-04 8.96916623e-04 3.84829259e-04 5.20625146e-10
 7.72355884e-04 1.02815228e-09 1.25655914e-03 1.58388923e-03]
Original Prior Mean SAT-D47 monthly:
 [16.27954224 17.01156006 18.66868896 21.54889648 27.12244995 32.0811853
 35.76927734 35.78623779 32.02878784 25.72896606 20.42561768 17.17369751]
Original Prior Standard Deviation SAT-D47 monthly:
 [3.46377896 3.10594374 2.78918732 2.54271169 2.46488387 2.73331005
 2.85535749 2.646315   2.52596201 3.00791784 3.58824735 3.69933077]
Updated Posterior Mean SAT-D47 monthly:
 [0.58384115 0.57819316 0.57212356 0.56538091 0.55283988 0.5417955
 0.5352128  0.53646114 0.54908711 0.56900319 0.58019837 0.58547234]
Updated Posterior Standard Deviation SAT-D47 monthly:
 [0.00205032 0.00212821 0.00216467 0.00213557 0.00197392 0.00179966
 0.00174475 0.00179853 0.0016947  0.00147584 0.00164494 0.00189799]
Original Prior Mean d18Oc monthly:
 [-0.87134431 -0.71613404 -0.7139883  -0.89894578 -1.51047705 -2.43504627
 -3.25136303 -3.57317763 -3.27234184 -2.5945588  -1.88634864 -1.25084057]
Original Prior Standard Deviation d18Oc monthly:
 [0.43074162 0.4079074  0.39792762 0.39889866 0.41067086 0.41700845
 0.43048772 0.48872905 0.56171093 0.58936283 0.51749387 0.46825537]
Updated Posterior Mean d18Oc monthly:
 [-0.0594466  -0.16160171 -0.22093518 -0.23611568 -0.55835238 -1.31067957
 -1.89449543 -2.11835829 -1.58325457 -0.69231214 -0.34526637 -0.09119921]
Updated Posterior Standard Deviation d18Oc monthly:
 [0.03807578 0.03552346 0.03066903 0.02830315 0.02933908 0.03518046
 0.04691073 0.04543986 0.04263553 0.05642311 0.04493518 0.03952293]
Original Prior Mean precipitation monthly:
 [2.05036495 2.09002108 2.13109892 1.96715635 1.40643449 1.6901619
 2.09515585 1.98018534 1.94212635 1.63982346 1.82765013 1.94334188]
Original Prior Standard Deviation precipitation monthly:
 [0.66564033 0.62619878 0.56043175 0.67673041 0.71392551 0.98128657
 1.25333983 1.00710893 0.75627296 0.48859499 0.68684095 0.68028201]
Updated Posterior Mean precipitation monthly:
 [1.05596221 1.25717489 1.73422117 2.1719024  1.62552508 1.90734963
 2.44764801 2.1186652  2.1632807  2.20086806 1.51119957 1.26216664]
Updated Posterior Standard Deviation precipitation monthly:
 [0.44758034 0.43024669 0.32290945 0.30670749 0.22057566 0.31346525
 0.41539167 0.4164468  0.5090759  0.38526466 0.29114281 0.29528475]

Update monthly priors from CESM 2x preindustrial pCO2 with aggregated data¶

  • Data and model outcomes aggregated in 12 months
  • No sclero-dating uncertainty
  • D47 Data aggregated per specimen and per month
In [66]:
# Apply Kalman function to update the prior with monthly data including updating the prec estimates
# Update the monthly D47 and prec prior with all measurements using block updating
monthly_aggregated_data = {} # Keep track of datapoints per season
n_update_CESM_2PIC = np.concatenate([mu_prior_CESM_2PIC_SST_D47_monthly * 0, mu_prior_CESM_2PIC_d18Oc_monthly * 0]) # Vector to store sample size per season for confidence interval plotting
weighted_sum_CESM_2PIC = np.concatenate([mu_prior_CESM_2PIC_SST_D47_monthly * 0, mu_prior_CESM_2PIC_d18Oc_monthly * 0]) # Vector to store mean temperature per season for confidence interval plotting
effective_weights_total_CESM_2PIC = np.concatenate([mu_prior_CESM_2PIC_SST_D47_monthly * 0, mu_prior_CESM_2PIC_d18Oc_monthly * 0]) # Vector to store temperature uncertainty per season for confidence interval plotting
mu_likelihood = np.concatenate([mu_prior_CESM_2PIC_SST_D47_monthly * 0, mu_prior_CESM_2PIC_d18Oc_monthly * 0]) # Vector to store mean temperature per season for confidence interval plotting
std_likelihood = np.concatenate([mu_prior_CESM_2PIC_SST_D47_monthly * 0, mu_prior_CESM_2PIC_d18Oc_monthly * 0]) # Vector to store temperature uncertainty per season for confidence interval plotting
var_names = ["D47_mean", "d18O"] # List of variable names which are updated
var_SD_names = ["D47_SD", "d18O_SD"] # List of names of variable uncertainties which are updated

# Update the prior with monthly data using the Kalman filter in block updating form
mu_post_CESM_2PIC, cov_post_CESM_2PIC = kalman_update_block(
    mu_prior_CESM_2PIC_monthly_combined,
    cov_prior_CESM_2PIC_monthly_combined,
    Z,
    R,
    H
)

# Extract the updated mean values from the combined state vector
mu_post_CESM_2PIC_SST_D47 = mu_post_CESM_2PIC[:len(mu_prior_CESM_2PIC_SST_D47_monthly)]
mu_post_CESM_2PIC_SAT_D47 = mu_post_CESM_2PIC[len(mu_prior_CESM_2PIC_SST_D47_monthly):2*len(mu_prior_CESM_2PIC_SST_D47_monthly)]
mu_post_CESM_2PIC_d18Oc = mu_post_CESM_2PIC[2*len(mu_prior_CESM_2PIC_SST_D47_monthly):3*len(mu_prior_CESM_2PIC_SST_D47_monthly)]
mu_post_CESM_2PIC_precip = mu_post_CESM_2PIC[3*len(mu_prior_CESM_2PIC_d18Oc_monthly):]

# Extract the updated covariance matrices from the combined covariance matrix
cov_post_CESM_2PIC_SST_D47 = cov_post_CESM_2PIC[:len(mu_prior_CESM_2PIC_SST_D47_monthly), :len(mu_prior_CESM_2PIC_SST_D47_monthly)]
cov_post_CESM_2PIC_SAT_D47 = cov_post_CESM_2PIC[len(mu_prior_CESM_2PIC_SST_D47_monthly):2*len(mu_prior_CESM_2PIC_SST_D47_monthly), len(mu_prior_CESM_2PIC_SST_D47_monthly):2*len(mu_prior_CESM_2PIC_SST_D47_monthly)]
cov_post_CESM_2PIC_d18Oc = cov_post_CESM_2PIC[2*len(mu_prior_CESM_2PIC_SST_D47_monthly):3*len(mu_prior_CESM_2PIC_SST_D47_monthly), 2*len(mu_prior_CESM_2PIC_SST_D47_monthly):3*len(mu_prior_CESM_2PIC_SST_D47_monthly)]
cov_post_CESM_2PIC_precip = cov_post_CESM_2PIC[3*len(mu_prior_CESM_2PIC_d18Oc_monthly):, 3*len(mu_prior_CESM_2PIC_d18Oc_monthly):]

for measurement in Lutetian_data_monthly_aggregated_dict: # Loop over measurements    
    # Track and update likelihood statistics
    weighted_sum_CESM_2PIC, effective_weights_total_CESM_2PIC, n_update_CESM_2PIC, monthly_aggregated_data = likelihood_statistics_multi(
        weighted_sum_CESM_2PIC,
        effective_weights_total_CESM_2PIC,
        n_update_CESM_2PIC,
        monthly_aggregated_data,
        measurement,
        timestamp = "month_score",
        timestamp_sd = "Month_err",
        Variable_names = var_names,
        Variable_names_SDs = var_SD_names
    )

# Normalize the weighted_sum_CESM_2PIC to obtain weighted mean
# Calculate inverse square root of the effective_weights_total_CESM_2PIC to contain the weighted standard deviation
# Print likelihood statistics
print("Likelihood statistics:")
num_vars = len(var_names)  # number of variables (e.g., D47, d18O)
num_bins_monthly = int(len(weighted_sum_CESM_2PIC) / num_vars)

for var_idx, var_name in enumerate(var_names):
    print(f"Results for variable: {var_name}")
    for bin_idx in range(num_bins_monthly):
        idx = var_idx * num_bins_monthly + bin_idx
        if effective_weights_total_CESM_2PIC[idx] is not None and effective_weights_total_CESM_2PIC[idx] != 0:
            mu_likelihood[idx] = weighted_sum_CESM_2PIC[idx] / effective_weights_total_CESM_2PIC[idx]
            std_likelihood[idx] = np.sqrt(1 / effective_weights_total_CESM_2PIC[idx])
        else:
            # If there are no data points for this bin, set the likelihood to NaN
            mu_likelihood[idx] = np.nan
            std_likelihood[idx] = np.nan
        print(f"  Bin {bin_idx + 1}:")
        print(f"    Weighted Average: {mu_likelihood[idx]}")
        print(f"    Aggregated Uncertainty: {std_likelihood[idx]}")
        print(f"    Number of Data Points: {n_update_CESM_2PIC[idx]}")
    print()

print("Original Prior Mean SST-D47 monthly:\n", mu_prior_CESM_2PIC_SST_D47_monthly_original)
print("Original Prior Standard Deviation SST-D47 monthly:\n", np.sqrt(np.diag(cov_prior_CESM_2PIC_SST_D47_monthly_original)))
print("Updated Posterior Mean SST-D47 monthly:\n", mu_post_CESM_2PIC_SST_D47)
print("Updated Posterior Standard Deviation SST-D47 monthly:\n", np.sqrt(np.diag(cov_post_CESM_2PIC_SST_D47)))
print("Original Prior Mean SAT-D47 monthly:\n", mu_prior_CESM_2PIC_SAT_monthly_original)
print("Original Prior Standard Deviation SAT-D47 monthly:\n", np.sqrt(np.diag(cov_prior_CESM_2PIC_SAT_monthly_original)))
print("Updated Posterior Mean SAT-D47 monthly:\n", mu_post_CESM_2PIC_SAT_D47)
print("Updated Posterior Standard Deviation SAT-D47 monthly:\n", np.sqrt(np.diag(cov_post_CESM_2PIC_SAT_D47)))
print("Original Prior Mean d18Oc monthly:\n", mu_prior_CESM_2PIC_d18Oc_monthly_original)
print("Original Prior Standard Deviation d18Oc monthly:\n", np.sqrt(np.diag(cov_prior_CESM_2PIC_d18Oc_monthly_original)))
print("Updated Posterior Mean d18Oc monthly:\n", mu_post_CESM_2PIC_d18Oc)
print("Updated Posterior Standard Deviation d18Oc monthly:\n", np.sqrt(np.diag(cov_post_CESM_2PIC_d18Oc)))
print("Original Prior Mean precipitation monthly:\n", mu_prior_CESM_2PIC_precip_monthly_original)
print("Original Prior Standard Deviation precipitation monthly:\n", np.sqrt(np.diag(cov_prior_CESM_2PIC_precip_monthly_original)))
print("Updated Posterior Mean precipitation monthly:\n", mu_post_CESM_2PIC_precip)
print("Updated Posterior Standard Deviation precipitation monthly:\n", np.sqrt(np.diag(cov_post_CESM_2PIC_precip)))
Likelihood statistics:
Results for variable: D47_mean
  Bin 1:
    Weighted Average: 0.6315000000000001
    Aggregated Uncertainty: 0.0145
    Number of Data Points: 1.0
  Bin 2:
    Weighted Average: 0.5964285714285714
    Aggregated Uncertainty: 0.01096096971726759
    Number of Data Points: 1.0
  Bin 3:
    Weighted Average: 0.6065
    Aggregated Uncertainty: 0.010253048327204941
    Number of Data Points: 1.0
  Bin 4:
    Weighted Average: nan
    Aggregated Uncertainty: nan
    Number of Data Points: 0.0
  Bin 5:
    Weighted Average: 0.5749687499999999
    Aggregated Uncertainty: 0.0051265241636024705
    Number of Data Points: 1.0
  Bin 6:
    Weighted Average: 0.5925625
    Aggregated Uncertainty: 0.00725
    Number of Data Points: 1.0
  Bin 7:
    Weighted Average: 0.5888260869565218
    Aggregated Uncertainty: 0.004275816728492018
    Number of Data Points: 1.0
  Bin 8:
    Weighted Average: nan
    Aggregated Uncertainty: nan
    Number of Data Points: 0.0
  Bin 9:
    Weighted Average: 0.5830000000000001
    Aggregated Uncertainty: 0.004973458969132757
    Number of Data Points: 1.0
  Bin 10:
    Weighted Average: nan
    Aggregated Uncertainty: nan
    Number of Data Points: 0.0
  Bin 11:
    Weighted Average: 0.594
    Aggregated Uncertainty: 0.011839200423452026
    Number of Data Points: 1.0
  Bin 12:
    Weighted Average: 0.5921333333333333
    Aggregated Uncertainty: 0.007487767802667672
    Number of Data Points: 1.0

Results for variable: d18O
  Bin 1:
    Weighted Average: 0.016000000000000014
    Aggregated Uncertainty: 0.0447213595499958
    Number of Data Points: 1.0
  Bin 2:
    Weighted Average: 0.10700000000000001
    Aggregated Uncertainty: 0.0316227766016838
    Number of Data Points: 1.0
  Bin 3:
    Weighted Average: -0.22615384615384615
    Aggregated Uncertainty: 0.02773500981126146
    Number of Data Points: 1.0
  Bin 4:
    Weighted Average: -0.5469999999999999
    Aggregated Uncertainty: 0.01414213562373095
    Number of Data Points: 1.0
  Bin 5:
    Weighted Average: -1.2017647058823526
    Aggregated Uncertainty: 0.009166984970282115
    Number of Data Points: 1.0
  Bin 6:
    Weighted Average: -1.6498290598290601
    Aggregated Uncertainty: 0.009245003270420488
    Number of Data Points: 1.0
  Bin 7:
    Weighted Average: -2.0610810810810816
    Aggregated Uncertainty: 0.009491579957524992
    Number of Data Points: 1.0
  Bin 8:
    Weighted Average: -1.7621904761904763
    Aggregated Uncertainty: 0.009759000729485335
    Number of Data Points: 1.0
  Bin 9:
    Weighted Average: -1.3562711864406782
    Aggregated Uncertainty: 0.009205746178983237
    Number of Data Points: 1.0
  Bin 10:
    Weighted Average: -0.5620833333333334
    Aggregated Uncertainty: 0.014433756729740647
    Number of Data Points: 1.0
  Bin 11:
    Weighted Average: -0.06419354838709676
    Aggregated Uncertainty: 0.017960530202677495
    Number of Data Points: 1.0
  Bin 12:
    Weighted Average: -0.162
    Aggregated Uncertainty: 0.0223606797749979
    Number of Data Points: 1.0

Original Prior Mean SST-D47 monthly:
 [0.60489442 0.60666426 0.60683094 0.60417118 0.59618643 0.58512465
 0.5755485  0.57189757 0.57548974 0.58366672 0.59236182 0.60038379]
Original Prior Standard Deviation SST-D47 monthly:
 [0.01009378 0.01057793 0.01042161 0.00955301 0.00826056 0.00738042
 0.0066458  0.00598658 0.00544544 0.0055813  0.00709986 0.00884544]
Updated Posterior Mean SST-D47 monthly:
 [0.60633943 0.60835679 0.60830884 0.60417118 0.59553875 0.58497423
 0.5756302  0.57189757 0.57513078 0.58366672 0.59201352 0.60122747]
Updated Posterior Standard Deviation SST-D47 monthly:
 [1.13760750e-03 7.29759587e-04 5.00967118e-04 9.38570330e-10
 6.43713775e-04 6.60290236e-04 6.33168776e-04 5.82076609e-10
 6.31370286e-04 1.16415322e-10 1.13779597e-03 1.42740787e-03]
Original Prior Mean SAT-D47 monthly:
 [13.07259888 13.64740356 15.16016968 18.37324585 23.23636963 27.22269897
 30.5027002  30.95843628 27.72623169 21.72160767 16.61921631 13.56875732]
Original Prior Standard Deviation SAT-D47 monthly:
 [3.54443863 3.25051999 2.97972364 2.6082818  2.44318742 2.633592
 2.9258649  2.76327261 2.72785837 3.26765855 3.74834864 3.87666334]
Updated Posterior Mean SAT-D47 monthly:
 [0.59641559 0.59232005 0.58723814 0.57894764 0.56739206 0.55832183
 0.55059838 0.55139891 0.56379469 0.58269717 0.59403101 0.5989389 ]
Updated Posterior Standard Deviation SAT-D47 monthly:
 [0.00238229 0.00246252 0.00250725 0.00247176 0.0022723  0.00210167
 0.00205337 0.0020195  0.00188792 0.00176289 0.00193812 0.00218669]
Original Prior Mean d18Oc monthly:
 [-0.20804548 -0.07873241 -0.07509482 -0.29063799 -0.90690032 -1.77413891
 -2.55085312 -2.84797432 -2.54024627 -1.8689654  -1.17633926 -0.55155968]
Original Prior Standard Deviation d18Oc monthly:
 [0.40225003 0.393072   0.38290499 0.36843204 0.36587289 0.37604721
 0.38016149 0.44783066 0.51482087 0.52320248 0.45863081 0.42027637]
Updated Posterior Mean d18Oc monthly:
 [-0.09222312 -0.13436748 -0.14611606 -0.20941588 -0.58108839 -1.28830361
 -1.97993509 -2.11259651 -1.48770687 -0.66398609 -0.31352031 -0.09363682]
Updated Posterior Standard Deviation d18Oc monthly:
 [0.04168471 0.03755797 0.03383831 0.03032566 0.02914058 0.03505934
 0.04651381 0.04561031 0.04852235 0.05893546 0.04279788 0.04020513]
Original Prior Mean precipitation monthly:
 [2.02240836 2.1888688  2.37645928 2.1330658  1.70077639 1.93969147
 2.35826096 2.03186492 1.81291405 1.57573304 2.40556723 2.22682322]
Original Prior Standard Deviation precipitation monthly:
 [0.71949004 0.82266634 0.74623178 0.7373264  0.8970992  1.16473376
 1.52905146 1.05236599 0.73902296 0.47685306 0.73744784 0.91193706]
Updated Posterior Mean precipitation monthly:
 [0.57809946 0.38905027 0.72943062 1.64125147 1.68506424 0.82097809
 2.01316514 1.74573788 1.30044782 1.65315879 1.38000985 1.49769403]
Updated Posterior Standard Deviation precipitation monthly:
 [0.51920344 0.61375606 0.53010315 0.34515565 0.2069392  0.47345971
 0.5604462  0.52280179 0.54586465 0.32693473 0.42293934 0.4186884 ]

Update monthly priors from HadCM (new) 1x preindustrial pCO2 with aggregated data¶

  • Data and model outcomes aggregated in 12 months
  • No sclero-dating uncertainty
  • D47 Data aggregated per specimen and per month
In [67]:
# Apply Kalman function to update the prior with monthly data including updating the prec estimates
# Update the monthly D47 and prec prior with all measurements using block updating
monthly_aggregated_data = {} # Keep track of datapoints per season
n_update_HadCM_new_1PIC = np.concatenate([mu_prior_HadCM_new_1PIC_SST_D47_monthly * 0, mu_prior_HadCM_new_1PIC_d18Oc_monthly * 0]) # Vector to store sample size per season for confidence interval plotting
weighted_sum_HadCM_new_1PIC = np.concatenate([mu_prior_HadCM_new_1PIC_SST_D47_monthly * 0, mu_prior_HadCM_new_1PIC_d18Oc_monthly * 0]) # Vector to store mean temperature per season for confidence interval plotting
effective_weights_total_HadCM_new_1PIC = np.concatenate([mu_prior_HadCM_new_1PIC_SST_D47_monthly * 0, mu_prior_HadCM_new_1PIC_d18Oc_monthly * 0]) # Vector to store temperature uncertainty per season for confidence interval plotting
mu_likelihood = np.concatenate([mu_prior_HadCM_new_1PIC_SST_D47_monthly * 0, mu_prior_HadCM_new_1PIC_d18Oc_monthly * 0]) # Vector to store mean temperature per season for confidence interval plotting
std_likelihood = np.concatenate([mu_prior_HadCM_new_1PIC_SST_D47_monthly * 0, mu_prior_HadCM_new_1PIC_d18Oc_monthly * 0]) # Vector to store temperature uncertainty per season for confidence interval plotting
var_names = ["D47_mean", "d18O"] # List of variable names which are updated
var_SD_names = ["D47_SD", "d18O_SD"] # List of names of variable uncertainties which are updated

# Update the prior with monthly data using the Kalman filter in block updating form
mu_post_HadCM_new_1PIC, cov_post_HadCM_new_1PIC = kalman_update_block(
    mu_prior_HadCM_new_1PIC_monthly_combined,
    cov_prior_HadCM_new_1PIC_monthly_combined,
    Z,
    R,
    H
)

# Extract the updated mean values from the combined state vector
mu_post_HadCM_new_1PIC_SST_D47 = mu_post_HadCM_new_1PIC[:len(mu_prior_HadCM_new_1PIC_SST_D47_monthly)]
mu_post_HadCM_new_1PIC_SAT_D47 = mu_post_HadCM_new_1PIC[len(mu_prior_HadCM_new_1PIC_SST_D47_monthly):2*len(mu_prior_HadCM_new_1PIC_SST_D47_monthly)]
mu_post_HadCM_new_1PIC_d18Oc = mu_post_HadCM_new_1PIC[2*len(mu_prior_HadCM_new_1PIC_SST_D47_monthly):3*len(mu_prior_HadCM_new_1PIC_SST_D47_monthly)]
mu_post_HadCM_new_1PIC_precip = mu_post_HadCM_new_1PIC[3*len(mu_prior_HadCM_new_1PIC_d18Oc_monthly):]

# Extract the updated covariance matrices from the combined covariance matrix
cov_post_HadCM_new_1PIC_SST_D47 = cov_post_HadCM_new_1PIC[:len(mu_prior_HadCM_new_1PIC_SST_D47_monthly), :len(mu_prior_HadCM_new_1PIC_SST_D47_monthly)]
cov_post_HadCM_new_1PIC_SAT_D47 = cov_post_HadCM_new_1PIC[len(mu_prior_HadCM_new_1PIC_SST_D47_monthly):2*len(mu_prior_HadCM_new_1PIC_SST_D47_monthly), len(mu_prior_HadCM_new_1PIC_SST_D47_monthly):2*len(mu_prior_HadCM_new_1PIC_SST_D47_monthly)]
cov_post_HadCM_new_1PIC_d18Oc = cov_post_HadCM_new_1PIC[2*len(mu_prior_HadCM_new_1PIC_SST_D47_monthly):3*len(mu_prior_HadCM_new_1PIC_SST_D47_monthly), 2*len(mu_prior_HadCM_new_1PIC_SST_D47_monthly):3*len(mu_prior_HadCM_new_1PIC_SST_D47_monthly)]
cov_post_HadCM_new_1PIC_precip = cov_post_HadCM_new_1PIC[3*len(mu_prior_HadCM_new_1PIC_d18Oc_monthly):, 3*len(mu_prior_HadCM_new_1PIC_d18Oc_monthly):]

for measurement in Lutetian_data_monthly_aggregated_dict: # Loop over measurements    
    # Track and update likelihood statistics
    weighted_sum_HadCM_new_1PIC, effective_weights_total_HadCM_new_1PIC, n_update_HadCM_new_1PIC, monthly_aggregated_data = likelihood_statistics_multi(
        weighted_sum_HadCM_new_1PIC,
        effective_weights_total_HadCM_new_1PIC,
        n_update_HadCM_new_1PIC,
        monthly_aggregated_data,
        measurement,
        timestamp = "month_score",
        timestamp_sd = "Month_err",
        Variable_names = var_names,
        Variable_names_SDs = var_SD_names
    )

# Normalize the weighted_sum_HadCM_new_1PIC to obtain weighted mean
# Calculate inverse square root of the effective_weights_total_HadCM_new_1PIC to contain the weighted standard deviation
# Print likelihood statistics
print("Likelihood statistics:")
num_vars = len(var_names)  # number of variables (e.g., D47, d18O)
num_bins_monthly = int(len(weighted_sum_HadCM_new_1PIC) / num_vars)

for var_idx, var_name in enumerate(var_names):
    print(f"Results for variable: {var_name}")
    for bin_idx in range(num_bins_monthly):
        idx = var_idx * num_bins_monthly + bin_idx
        if effective_weights_total_HadCM_new_1PIC[idx] is not None and effective_weights_total_HadCM_new_1PIC[idx] != 0:
            mu_likelihood[idx] = weighted_sum_HadCM_new_1PIC[idx] / effective_weights_total_HadCM_new_1PIC[idx]
            std_likelihood[idx] = np.sqrt(1 / effective_weights_total_HadCM_new_1PIC[idx])
        else:
            # If there are no data points for this bin, set the likelihood to NaN
            mu_likelihood[idx] = np.nan
            std_likelihood[idx] = np.nan
        print(f"  Bin {bin_idx + 1}:")
        print(f"    Weighted Average: {mu_likelihood[idx]}")
        print(f"    Aggregated Uncertainty: {std_likelihood[idx]}")
        print(f"    Number of Data Points: {n_update_HadCM_new_1PIC[idx]}")
    print()

print("Original Prior Mean SST-D47 monthly:\n", mu_prior_HadCM_new_1PIC_SST_D47_monthly_original)
print("Original Prior Standard Deviation SST-D47 monthly:\n", np.sqrt(np.diag(cov_prior_HadCM_new_1PIC_SST_D47_monthly_original)))
print("Updated Posterior Mean SST-D47 monthly:\n", mu_post_HadCM_new_1PIC_SST_D47)
print("Updated Posterior Standard Deviation SST-D47 monthly:\n", np.sqrt(np.diag(cov_post_HadCM_new_1PIC_SST_D47)))
print("Original Prior Mean SAT-D47 monthly:\n", mu_prior_HadCM_new_1PIC_SAT_monthly_original)
print("Original Prior Standard Deviation SAT-D47 monthly:\n", np.sqrt(np.diag(cov_prior_HadCM_new_1PIC_SAT_monthly_original)))
print("Updated Posterior Mean SAT-D47 monthly:\n", mu_post_HadCM_new_1PIC_SAT_D47)
print("Updated Posterior Standard Deviation SAT-D47 monthly:\n", np.sqrt(np.diag(cov_post_HadCM_new_1PIC_SAT_D47)))
print("Original Prior Mean d18Oc monthly:\n", mu_prior_HadCM_new_1PIC_d18Oc_monthly_original)
print("Original Prior Standard Deviation d18Oc monthly:\n", np.sqrt(np.diag(cov_prior_HadCM_new_1PIC_d18Oc_monthly_original)))
print("Updated Posterior Mean d18Oc monthly:\n", mu_post_HadCM_new_1PIC_d18Oc)
print("Updated Posterior Standard Deviation d18Oc monthly:\n", np.sqrt(np.diag(cov_post_HadCM_new_1PIC_d18Oc)))
print("Original Prior Mean precipitation monthly:\n", mu_prior_HadCM_new_1PIC_precip_monthly_original)
print("Original Prior Standard Deviation precipitation monthly:\n", np.sqrt(np.diag(cov_prior_HadCM_new_1PIC_precip_monthly_original)))
print("Updated Posterior Mean precipitation monthly:\n", mu_post_HadCM_new_1PIC_precip)
print("Updated Posterior Standard Deviation precipitation monthly:\n", np.sqrt(np.diag(cov_post_HadCM_new_1PIC_precip)))
Likelihood statistics:
Results for variable: D47_mean
  Bin 1:
    Weighted Average: 0.6315000000000001
    Aggregated Uncertainty: 0.0145
    Number of Data Points: 1.0
  Bin 2:
    Weighted Average: 0.5964285714285714
    Aggregated Uncertainty: 0.01096096971726759
    Number of Data Points: 1.0
  Bin 3:
    Weighted Average: 0.6065
    Aggregated Uncertainty: 0.010253048327204941
    Number of Data Points: 1.0
  Bin 4:
    Weighted Average: nan
    Aggregated Uncertainty: nan
    Number of Data Points: 0.0
  Bin 5:
    Weighted Average: 0.5749687499999999
    Aggregated Uncertainty: 0.0051265241636024705
    Number of Data Points: 1.0
  Bin 6:
    Weighted Average: 0.5925625
    Aggregated Uncertainty: 0.00725
    Number of Data Points: 1.0
  Bin 7:
    Weighted Average: 0.5888260869565218
    Aggregated Uncertainty: 0.004275816728492018
    Number of Data Points: 1.0
  Bin 8:
    Weighted Average: nan
    Aggregated Uncertainty: nan
    Number of Data Points: 0.0
  Bin 9:
    Weighted Average: 0.5830000000000001
    Aggregated Uncertainty: 0.004973458969132757
    Number of Data Points: 1.0
  Bin 10:
    Weighted Average: nan
    Aggregated Uncertainty: nan
    Number of Data Points: 0.0
  Bin 11:
    Weighted Average: 0.594
    Aggregated Uncertainty: 0.011839200423452026
    Number of Data Points: 1.0
  Bin 12:
    Weighted Average: 0.5921333333333333
    Aggregated Uncertainty: 0.007487767802667672
    Number of Data Points: 1.0

Results for variable: d18O
  Bin 1:
    Weighted Average: 0.016000000000000014
    Aggregated Uncertainty: 0.0447213595499958
    Number of Data Points: 1.0
  Bin 2:
    Weighted Average: 0.10700000000000001
    Aggregated Uncertainty: 0.0316227766016838
    Number of Data Points: 1.0
  Bin 3:
    Weighted Average: -0.22615384615384615
    Aggregated Uncertainty: 0.02773500981126146
    Number of Data Points: 1.0
  Bin 4:
    Weighted Average: -0.5469999999999999
    Aggregated Uncertainty: 0.01414213562373095
    Number of Data Points: 1.0
  Bin 5:
    Weighted Average: -1.2017647058823526
    Aggregated Uncertainty: 0.009166984970282115
    Number of Data Points: 1.0
  Bin 6:
    Weighted Average: -1.6498290598290601
    Aggregated Uncertainty: 0.009245003270420488
    Number of Data Points: 1.0
  Bin 7:
    Weighted Average: -2.0610810810810816
    Aggregated Uncertainty: 0.009491579957524992
    Number of Data Points: 1.0
  Bin 8:
    Weighted Average: -1.7621904761904763
    Aggregated Uncertainty: 0.009759000729485335
    Number of Data Points: 1.0
  Bin 9:
    Weighted Average: -1.3562711864406782
    Aggregated Uncertainty: 0.009205746178983237
    Number of Data Points: 1.0
  Bin 10:
    Weighted Average: -0.5620833333333334
    Aggregated Uncertainty: 0.014433756729740647
    Number of Data Points: 1.0
  Bin 11:
    Weighted Average: -0.06419354838709676
    Aggregated Uncertainty: 0.017960530202677495
    Number of Data Points: 1.0
  Bin 12:
    Weighted Average: -0.162
    Aggregated Uncertainty: 0.0223606797749979
    Number of Data Points: 1.0

Original Prior Mean SST-D47 monthly:
 [0.62836703 0.63114362 0.6315288  0.62910984 0.62039478 0.60379994
 0.59226822 0.58947313 0.5946067  0.60517016 0.61565939 0.62340158]
Original Prior Standard Deviation SST-D47 monthly:
 [0.01239925 0.01298432 0.01278486 0.01157278 0.00894292 0.00575495
 0.00332249 0.00262989 0.0050293  0.00800725 0.0098363  0.01123015]
Updated Posterior Mean SST-D47 monthly:
 [0.6148096  0.62053421 0.625955   0.62910984 0.62665477 0.61089807
 0.59512173 0.58947313 0.59479705 0.60517016 0.6125581  0.61409802]
Updated Posterior Standard Deviation SST-D47 monthly:
 [7.97462698e-04 7.16214541e-04 4.59243610e-04 1.84436556e-09
 5.73810778e-04 6.87700310e-04 2.06448258e-04 4.92190434e-10
 1.20030181e-04 1.61729334e-09 1.44899233e-04 4.85196679e-04]
Original Prior Mean SAT-D47 monthly:
 [10.08334503 10.0055481  10.76345469 12.26940816 15.83041026 20.84376678
 24.38166707 25.21004893 23.2913503  19.00565236 14.61674144 11.84420675]
Original Prior Standard Deviation SAT-D47 monthly:
 [3.96689536 3.6677536  3.37467091 2.96255495 2.3892861  1.69618705
 1.01561685 0.897383   1.69453479 2.75833427 3.47391248 3.86029272]
Updated Posterior Mean SAT-D47 monthly:
 [0.60360563 0.60377625 0.60087487 0.59615204 0.58934856 0.58098627
 0.57634057 0.5780185  0.58035622 0.58635895 0.59559924 0.600128  ]
Updated Posterior Standard Deviation SAT-D47 monthly:
 [0.00080107 0.0008285  0.0008224  0.0009281  0.00108508 0.00092428
 0.00067118 0.00053011 0.0004584  0.00066915 0.00084274 0.00085404]
Original Prior Mean d18Oc monthly:
 [ 1.96163182  2.15696186  2.18020776  2.0017259   1.36800588  0.1424221
 -0.73896791 -0.96534146 -0.5598614   0.26223308  1.0455347   1.60694956]
Original Prior Standard Deviation d18Oc monthly:
 [0.74655093 0.78001576 0.76607827 0.69073309 0.52749869 0.32304877
 0.16440636 0.12281718 0.28404232 0.48860193 0.59855519 0.67791903]
Updated Posterior Mean d18Oc monthly:
 [-0.06605668  0.09116253  0.0664248  -0.11401332 -0.46110761 -1.25769733
 -1.71707111 -1.59985516 -1.42991687 -1.07534712 -0.54037574 -0.25722263]
Updated Posterior Standard Deviation d18Oc monthly:
 [0.04584503 0.05021895 0.04482341 0.04222399 0.04981098 0.04682638
 0.04662781 0.04847023 0.03337761 0.03412356 0.04354023 0.04498715]
Original Prior Mean precipitation monthly:
 [2.93467813 2.51780503 2.36863809 2.23043843 2.39540224 2.0227101
 3.48519517 3.86902922 3.50113248 3.86729931 3.88739363 3.5501087 ]
Original Prior Standard Deviation precipitation monthly:
 [0.55099183 0.33959534 0.30486469 0.38027225 0.8389547  1.13985648
 1.28457778 0.88043538 0.83027462 0.81630782 0.57832729 0.61808957]
Updated Posterior Mean precipitation monthly:
 [5.8602765  5.15454372 3.91008794 3.01792761 1.34490261 0.7967566
 5.24010718 8.08328405 7.25484027 8.73891028 7.15872439 6.85176391]
Updated Posterior Standard Deviation precipitation monthly:
 [0.25263177 0.22162949 0.19905823 0.15814356 0.31922835 0.2508503
 0.38713572 0.36478263 0.579605   0.4842891  0.38831833 0.31256322]

Update monthly priors from HadCM (new) 2x preindustrial pCO2 with aggregated data¶

  • Data and model outcomes aggregated in 12 months
  • No sclero-dating uncertainty
  • D47 Data aggregated per specimen and per month
In [68]:
# Apply Kalman function to update the prior with monthly data including updating the prec estimates
# Update the monthly D47 and prec prior with all measurements using block updating
monthly_aggregated_data = {} # Keep track of datapoints per season
n_update_HadCM_new_2PIC = np.concatenate([mu_prior_HadCM_new_2PIC_SST_D47_monthly * 0, mu_prior_HadCM_new_2PIC_d18Oc_monthly * 0]) # Vector to store sample size per season for confidence interval plotting
weighted_sum_HadCM_new_2PIC = np.concatenate([mu_prior_HadCM_new_2PIC_SST_D47_monthly * 0, mu_prior_HadCM_new_2PIC_d18Oc_monthly * 0]) # Vector to store mean temperature per season for confidence interval plotting
effective_weights_total_HadCM_new_2PIC = np.concatenate([mu_prior_HadCM_new_2PIC_SST_D47_monthly * 0, mu_prior_HadCM_new_2PIC_d18Oc_monthly * 0]) # Vector to store temperature uncertainty per season for confidence interval plotting
mu_likelihood = np.concatenate([mu_prior_HadCM_new_2PIC_SST_D47_monthly * 0, mu_prior_HadCM_new_2PIC_d18Oc_monthly * 0]) # Vector to store mean temperature per season for confidence interval plotting
std_likelihood = np.concatenate([mu_prior_HadCM_new_2PIC_SST_D47_monthly * 0, mu_prior_HadCM_new_2PIC_d18Oc_monthly * 0]) # Vector to store temperature uncertainty per season for confidence interval plotting
var_names = ["D47_mean", "d18O"] # List of variable names which are updated
var_SD_names = ["D47_SD", "d18O_SD"] # List of names of variable uncertainties which are updated

# Update the prior with monthly data using the Kalman filter in block updating form
mu_post_HadCM_new_2PIC, cov_post_HadCM_new_2PIC = kalman_update_block(
    mu_prior_HadCM_new_2PIC_monthly_combined,
    cov_prior_HadCM_new_2PIC_monthly_combined,
    Z,
    R,
    H
)

# Extract the updated mean values from the combined state vector
mu_post_HadCM_new_2PIC_SST_D47 = mu_post_HadCM_new_2PIC[:len(mu_prior_HadCM_new_2PIC_SST_D47_monthly)]
mu_post_HadCM_new_2PIC_SAT_D47 = mu_post_HadCM_new_2PIC[len(mu_prior_HadCM_new_2PIC_SST_D47_monthly):2*len(mu_prior_HadCM_new_2PIC_SST_D47_monthly)]
mu_post_HadCM_new_2PIC_d18Oc = mu_post_HadCM_new_2PIC[2*len(mu_prior_HadCM_new_2PIC_SST_D47_monthly):3*len(mu_prior_HadCM_new_2PIC_SST_D47_monthly)]
mu_post_HadCM_new_2PIC_precip = mu_post_HadCM_new_2PIC[3*len(mu_prior_HadCM_new_2PIC_d18Oc_monthly):]

# Extract the updated covariance matrices from the combined covariance matrix
cov_post_HadCM_new_2PIC_SST_D47 = cov_post_HadCM_new_2PIC[:len(mu_prior_HadCM_new_2PIC_SST_D47_monthly), :len(mu_prior_HadCM_new_2PIC_SST_D47_monthly)]
cov_post_HadCM_new_2PIC_SAT_D47 = cov_post_HadCM_new_2PIC[len(mu_prior_HadCM_new_2PIC_SST_D47_monthly):2*len(mu_prior_HadCM_new_2PIC_SST_D47_monthly), len(mu_prior_HadCM_new_2PIC_SST_D47_monthly):2*len(mu_prior_HadCM_new_2PIC_SST_D47_monthly)]
cov_post_HadCM_new_2PIC_d18Oc = cov_post_HadCM_new_2PIC[2*len(mu_prior_HadCM_new_2PIC_SST_D47_monthly):3*len(mu_prior_HadCM_new_2PIC_SST_D47_monthly), 2*len(mu_prior_HadCM_new_2PIC_SST_D47_monthly):3*len(mu_prior_HadCM_new_2PIC_SST_D47_monthly)]
cov_post_HadCM_new_2PIC_precip = cov_post_HadCM_new_2PIC[3*len(mu_prior_HadCM_new_2PIC_d18Oc_monthly):, 3*len(mu_prior_HadCM_new_2PIC_d18Oc_monthly):]

for measurement in Lutetian_data_monthly_aggregated_dict: # Loop over measurements    
    # Track and update likelihood statistics
    weighted_sum_HadCM_new_2PIC, effective_weights_total_HadCM_new_2PIC, n_update_HadCM_new_2PIC, monthly_aggregated_data = likelihood_statistics_multi(
        weighted_sum_HadCM_new_2PIC,
        effective_weights_total_HadCM_new_2PIC,
        n_update_HadCM_new_2PIC,
        monthly_aggregated_data,
        measurement,
        timestamp = "month_score",
        timestamp_sd = "Month_err",
        Variable_names = var_names,
        Variable_names_SDs = var_SD_names
    )

# Normalize the weighted_sum_HadCM_new_2PIC to obtain weighted mean
# Calculate inverse square root of the effective_weights_total_HadCM_new_2PIC to contain the weighted standard deviation
# Print likelihood statistics
print("Likelihood statistics:")
num_vars = len(var_names)  # number of variables (e.g., D47, d18O)
num_bins_monthly = int(len(weighted_sum_HadCM_new_2PIC) / num_vars)

for var_idx, var_name in enumerate(var_names):
    print(f"Results for variable: {var_name}")
    for bin_idx in range(num_bins_monthly):
        idx = var_idx * num_bins_monthly + bin_idx
        if effective_weights_total_HadCM_new_2PIC[idx] is not None and effective_weights_total_HadCM_new_2PIC[idx] != 0:
            mu_likelihood[idx] = weighted_sum_HadCM_new_2PIC[idx] / effective_weights_total_HadCM_new_2PIC[idx]
            std_likelihood[idx] = np.sqrt(1 / effective_weights_total_HadCM_new_2PIC[idx])
        else:
            # If there are no data points for this bin, set the likelihood to NaN
            mu_likelihood[idx] = np.nan
            std_likelihood[idx] = np.nan
        print(f"  Bin {bin_idx + 1}:")
        print(f"    Weighted Average: {mu_likelihood[idx]}")
        print(f"    Aggregated Uncertainty: {std_likelihood[idx]}")
        print(f"    Number of Data Points: {n_update_HadCM_new_2PIC[idx]}")
    print()

print("Original Prior Mean SST-D47 monthly:\n", mu_prior_HadCM_new_2PIC_SST_D47_monthly_original)
print("Original Prior Standard Deviation SST-D47 monthly:\n", np.sqrt(np.diag(cov_prior_HadCM_new_2PIC_SST_D47_monthly_original)))
print("Updated Posterior Mean SST-D47 monthly:\n", mu_post_HadCM_new_2PIC_SST_D47)
print("Updated Posterior Standard Deviation SST-D47 monthly:\n", np.sqrt(np.diag(cov_post_HadCM_new_2PIC_SST_D47)))
print("Original Prior Mean SAT-D47 monthly:\n", mu_prior_HadCM_new_2PIC_SAT_monthly_original)
print("Original Prior Standard Deviation SAT-D47 monthly:\n", np.sqrt(np.diag(cov_prior_HadCM_new_2PIC_SAT_monthly_original)))
print("Updated Posterior Mean SAT-D47 monthly:\n", mu_post_HadCM_new_2PIC_SAT_D47)
print("Updated Posterior Standard Deviation SAT-D47 monthly:\n", np.sqrt(np.diag(cov_post_HadCM_new_2PIC_SAT_D47)))
print("Original Prior Mean d18Oc monthly:\n", mu_prior_HadCM_new_2PIC_d18Oc_monthly_original)
print("Original Prior Standard Deviation d18Oc monthly:\n", np.sqrt(np.diag(cov_prior_HadCM_new_2PIC_d18Oc_monthly_original)))
print("Updated Posterior Mean d18Oc monthly:\n", mu_post_HadCM_new_2PIC_d18Oc)
print("Updated Posterior Standard Deviation d18Oc monthly:\n", np.sqrt(np.diag(cov_post_HadCM_new_2PIC_d18Oc)))
print("Original Prior Mean precipitation monthly:\n", mu_prior_HadCM_new_2PIC_precip_monthly_original)
print("Original Prior Standard Deviation precipitation monthly:\n", np.sqrt(np.diag(cov_prior_HadCM_new_2PIC_precip_monthly_original)))
print("Updated Posterior Mean precipitation monthly:\n", mu_post_HadCM_new_2PIC_precip)
print("Updated Posterior Standard Deviation precipitation monthly:\n", np.sqrt(np.diag(cov_post_HadCM_new_2PIC_precip)))
Likelihood statistics:
Results for variable: D47_mean
  Bin 1:
    Weighted Average: 0.6315000000000001
    Aggregated Uncertainty: 0.0145
    Number of Data Points: 1.0
  Bin 2:
    Weighted Average: 0.5964285714285714
    Aggregated Uncertainty: 0.01096096971726759
    Number of Data Points: 1.0
  Bin 3:
    Weighted Average: 0.6065
    Aggregated Uncertainty: 0.010253048327204941
    Number of Data Points: 1.0
  Bin 4:
    Weighted Average: nan
    Aggregated Uncertainty: nan
    Number of Data Points: 0.0
  Bin 5:
    Weighted Average: 0.5749687499999999
    Aggregated Uncertainty: 0.0051265241636024705
    Number of Data Points: 1.0
  Bin 6:
    Weighted Average: 0.5925625
    Aggregated Uncertainty: 0.00725
    Number of Data Points: 1.0
  Bin 7:
    Weighted Average: 0.5888260869565218
    Aggregated Uncertainty: 0.004275816728492018
    Number of Data Points: 1.0
  Bin 8:
    Weighted Average: nan
    Aggregated Uncertainty: nan
    Number of Data Points: 0.0
  Bin 9:
    Weighted Average: 0.5830000000000001
    Aggregated Uncertainty: 0.004973458969132757
    Number of Data Points: 1.0
  Bin 10:
    Weighted Average: nan
    Aggregated Uncertainty: nan
    Number of Data Points: 0.0
  Bin 11:
    Weighted Average: 0.594
    Aggregated Uncertainty: 0.011839200423452026
    Number of Data Points: 1.0
  Bin 12:
    Weighted Average: 0.5921333333333333
    Aggregated Uncertainty: 0.007487767802667672
    Number of Data Points: 1.0

Results for variable: d18O
  Bin 1:
    Weighted Average: 0.016000000000000014
    Aggregated Uncertainty: 0.0447213595499958
    Number of Data Points: 1.0
  Bin 2:
    Weighted Average: 0.10700000000000001
    Aggregated Uncertainty: 0.0316227766016838
    Number of Data Points: 1.0
  Bin 3:
    Weighted Average: -0.22615384615384615
    Aggregated Uncertainty: 0.02773500981126146
    Number of Data Points: 1.0
  Bin 4:
    Weighted Average: -0.5469999999999999
    Aggregated Uncertainty: 0.01414213562373095
    Number of Data Points: 1.0
  Bin 5:
    Weighted Average: -1.2017647058823526
    Aggregated Uncertainty: 0.009166984970282115
    Number of Data Points: 1.0
  Bin 6:
    Weighted Average: -1.6498290598290601
    Aggregated Uncertainty: 0.009245003270420488
    Number of Data Points: 1.0
  Bin 7:
    Weighted Average: -2.0610810810810816
    Aggregated Uncertainty: 0.009491579957524992
    Number of Data Points: 1.0
  Bin 8:
    Weighted Average: -1.7621904761904763
    Aggregated Uncertainty: 0.009759000729485335
    Number of Data Points: 1.0
  Bin 9:
    Weighted Average: -1.3562711864406782
    Aggregated Uncertainty: 0.009205746178983237
    Number of Data Points: 1.0
  Bin 10:
    Weighted Average: -0.5620833333333334
    Aggregated Uncertainty: 0.014433756729740647
    Number of Data Points: 1.0
  Bin 11:
    Weighted Average: -0.06419354838709676
    Aggregated Uncertainty: 0.017960530202677495
    Number of Data Points: 1.0
  Bin 12:
    Weighted Average: -0.162
    Aggregated Uncertainty: 0.0223606797749979
    Number of Data Points: 1.0

Original Prior Mean SST-D47 monthly:
 [0.61875389 0.62144134 0.62169674 0.61911904 0.61021893 0.59447415
 0.58422233 0.58195388 0.58646513 0.59640058 0.60652689 0.6140889 ]
Original Prior Standard Deviation SST-D47 monthly:
 [0.01040204 0.0109815  0.01071872 0.00954875 0.00690416 0.00357276
 0.0021291  0.00205074 0.00405515 0.00645973 0.00802654 0.00939622]
Updated Posterior Mean SST-D47 monthly:
 [0.61113523 0.61445579 0.61847325 0.61911904 0.61474574 0.59844603
 0.58550682 0.58195388 0.58620523 0.59640058 0.60399661 0.60847355]
Updated Posterior Standard Deviation SST-D47 monthly:
 [7.28066386e-04 7.51791821e-04 4.53569647e-04            nan
 5.24531844e-04 7.42927977e-04 2.40789615e-04 8.73114914e-11
 1.39860920e-04            nan 3.05217858e-04 4.57073846e-04]
Original Prior Mean SAT-D47 monthly:
 [13.87478027 13.46100006 14.24293162 15.6019455  19.14669444 24.01290283
 27.19336853 27.86939901 26.06070608 22.21917877 18.0738032  15.42517497]
Original Prior Standard Deviation SAT-D47 monthly:
 [3.41347899 3.22229019 2.87469713 2.50385319 1.86477108 0.98233555
 0.60279527 0.70411706 1.43557583 2.29931143 2.93579974 3.37321414]
Updated Posterior Mean SAT-D47 monthly:
 [0.60476992 0.60636119 0.60397325 0.59975206 0.59206809 0.58318837
 0.57547163 0.57449337 0.57672616 0.58354035 0.59410683 0.60049259]
Updated Posterior Standard Deviation SAT-D47 monthly:
 [0.00080618 0.00082199 0.00081947 0.00092336 0.00103791 0.00080346
 0.0004974  0.00039912 0.00054103 0.00070553 0.0008199  0.00085221]
Original Prior Mean d18Oc monthly:
 [ 1.34651655  1.53819119  1.55333874  1.36348944  0.70137078 -0.48997468
 -1.28354475 -1.47094578 -1.10453    -0.31671952  0.4525012   1.00989248]
Original Prior Standard Deviation d18Oc monthly:
 [0.63262645 0.66808051 0.64945684 0.57332803 0.39872414 0.16768838
 0.11737359 0.11506852 0.2109833  0.38622828 0.48685033 0.57123617]
Updated Posterior Mean d18Oc monthly:
 [ 0.07829132  0.2587271   0.25832613  0.07199784 -0.3699015  -1.19892008
 -1.83252468 -1.8512603  -1.71970195 -1.27483028 -0.61579703 -0.18889576]
Updated Posterior Standard Deviation d18Oc monthly:
 [0.04499777 0.04762118 0.04199768 0.04114147 0.04705045 0.0472996
 0.0421032  0.03960723 0.02881555 0.03221767 0.04247287 0.04588428]
Original Prior Mean precipitation monthly:
 [3.80580454 3.16736692 2.40405854 2.33888872 2.90959791 1.9625486
 3.35601807 3.95611436 3.35655003 3.81088675 4.52821999 4.18951223]
Original Prior Standard Deviation precipitation monthly:
 [0.74624594 0.55008635 0.35552588 0.43694453 1.02178189 1.04182468
 1.29200533 1.14999034 0.7361767  0.88765985 0.78936416 0.72873753]
Updated Posterior Mean precipitation monthly:
 [7.98378055 6.11711225 3.74212789 3.40646899 3.37132175 0.67361506
 6.62209357 9.59845192 7.08947814 7.17663163 9.42631991 8.18922726]
Updated Posterior Standard Deviation precipitation monthly:
 [0.41640318 0.33531479 0.25143332 0.24371404 0.31880486 0.33027699
 0.35702858 0.46088042 0.52869844 0.52717301 0.55469325 0.4343936 ]
C:\Users\nwi213\AppData\Local\Temp\ipykernel_4724\414881667.py:74: RuntimeWarning: invalid value encountered in sqrt
  print("Updated Posterior Standard Deviation SST-D47 monthly:\n", np.sqrt(np.diag(cov_post_HadCM_new_2PIC_SST_D47)))

Update monthly priors from HadCM (new) 1056 ppm pCO2 with aggregated data¶

  • Data and model outcomes aggregated in 12 months
  • No sclero-dating uncertainty
  • D47 Data aggregated per specimen and per month
In [69]:
# Apply Kalman function to update the prior with monthly data including updating the prec estimates
# Update the monthly D47 and prec prior with all measurements using block updating
monthly_aggregated_data = {} # Keep track of datapoints per season
n_update_HadCM_new_1056ppm = np.concatenate([mu_prior_HadCM_new_1056ppm_SST_D47_monthly * 0, mu_prior_HadCM_new_1056ppm_d18Oc_monthly * 0]) # Vector to store sample size per season for confidence interval plotting
weighted_sum_HadCM_new_1056ppm = np.concatenate([mu_prior_HadCM_new_1056ppm_SST_D47_monthly * 0, mu_prior_HadCM_new_1056ppm_d18Oc_monthly * 0]) # Vector to store mean temperature per season for confidence interval plotting
effective_weights_total_HadCM_new_1056ppm = np.concatenate([mu_prior_HadCM_new_1056ppm_SST_D47_monthly * 0, mu_prior_HadCM_new_1056ppm_d18Oc_monthly * 0]) # Vector to store temperature uncertainty per season for confidence interval plotting
mu_likelihood = np.concatenate([mu_prior_HadCM_new_1056ppm_SST_D47_monthly * 0, mu_prior_HadCM_new_1056ppm_d18Oc_monthly * 0]) # Vector to store mean temperature per season for confidence interval plotting
std_likelihood = np.concatenate([mu_prior_HadCM_new_1056ppm_SST_D47_monthly * 0, mu_prior_HadCM_new_1056ppm_d18Oc_monthly * 0]) # Vector to store temperature uncertainty per season for confidence interval plotting
var_names = ["D47_mean", "d18O"] # List of variable names which are updated
var_SD_names = ["D47_SD", "d18O_SD"] # List of names of variable uncertainties which are updated

# Update the prior with monthly data using the Kalman filter in block updating form
mu_post_HadCM_new_1056ppm, cov_post_HadCM_new_1056ppm = kalman_update_block(
    mu_prior_HadCM_new_1056ppm_monthly_combined,
    cov_prior_HadCM_new_1056ppm_monthly_combined,
    Z,
    R,
    H
)

# Extract the updated mean values from the combined state vector
mu_post_HadCM_new_1056ppm_SST_D47 = mu_post_HadCM_new_1056ppm[:len(mu_prior_HadCM_new_1056ppm_SST_D47_monthly)]
mu_post_HadCM_new_1056ppm_SAT_D47 = mu_post_HadCM_new_1056ppm[len(mu_prior_HadCM_new_1056ppm_SST_D47_monthly):2*len(mu_prior_HadCM_new_1056ppm_SST_D47_monthly)]
mu_post_HadCM_new_1056ppm_d18Oc = mu_post_HadCM_new_1056ppm[2*len(mu_prior_HadCM_new_1056ppm_SST_D47_monthly):3*len(mu_prior_HadCM_new_1056ppm_SST_D47_monthly)]
mu_post_HadCM_new_1056ppm_precip = mu_post_HadCM_new_1056ppm[3*len(mu_prior_HadCM_new_1056ppm_d18Oc_monthly):]

# Extract the updated covariance matrices from the combined covariance matrix
cov_post_HadCM_new_1056ppm_SST_D47 = cov_post_HadCM_new_1056ppm[:len(mu_prior_HadCM_new_1056ppm_SST_D47_monthly), :len(mu_prior_HadCM_new_1056ppm_SST_D47_monthly)]
cov_post_HadCM_new_1056ppm_SAT_D47 = cov_post_HadCM_new_1056ppm[len(mu_prior_HadCM_new_1056ppm_SST_D47_monthly):2*len(mu_prior_HadCM_new_1056ppm_SST_D47_monthly), len(mu_prior_HadCM_new_1056ppm_SST_D47_monthly):2*len(mu_prior_HadCM_new_1056ppm_SST_D47_monthly)]
cov_post_HadCM_new_1056ppm_d18Oc = cov_post_HadCM_new_1056ppm[2*len(mu_prior_HadCM_new_1056ppm_SST_D47_monthly):3*len(mu_prior_HadCM_new_1056ppm_SST_D47_monthly), 2*len(mu_prior_HadCM_new_1056ppm_SST_D47_monthly):3*len(mu_prior_HadCM_new_1056ppm_SST_D47_monthly)]
cov_post_HadCM_new_1056ppm_precip = cov_post_HadCM_new_1056ppm[3*len(mu_prior_HadCM_new_1056ppm_d18Oc_monthly):, 3*len(mu_prior_HadCM_new_1056ppm_d18Oc_monthly):]

for measurement in Lutetian_data_monthly_aggregated_dict: # Loop over measurements    
    # Track and update likelihood statistics
    weighted_sum_HadCM_new_1056ppm, effective_weights_total_HadCM_new_1056ppm, n_update_HadCM_new_1056ppm, monthly_aggregated_data = likelihood_statistics_multi(
        weighted_sum_HadCM_new_1056ppm,
        effective_weights_total_HadCM_new_1056ppm,
        n_update_HadCM_new_1056ppm,
        monthly_aggregated_data,
        measurement,
        timestamp = "month_score",
        timestamp_sd = "Month_err",
        Variable_names = var_names,
        Variable_names_SDs = var_SD_names
    )

# Normalize the weighted_sum_HadCM_new_1056ppm to obtain weighted mean
# Calculate inverse square root of the effective_weights_total_HadCM_new_1056ppm to contain the weighted standard deviation
# Print likelihood statistics
print("Likelihood statistics:")
num_vars = len(var_names)  # number of variables (e.g., D47, d18O)
num_bins_monthly = int(len(weighted_sum_HadCM_new_1056ppm) / num_vars)

for var_idx, var_name in enumerate(var_names):
    print(f"Results for variable: {var_name}")
    for bin_idx in range(num_bins_monthly):
        idx = var_idx * num_bins_monthly + bin_idx
        if effective_weights_total_HadCM_new_1056ppm[idx] is not None and effective_weights_total_HadCM_new_1056ppm[idx] != 0:
            mu_likelihood[idx] = weighted_sum_HadCM_new_1056ppm[idx] / effective_weights_total_HadCM_new_1056ppm[idx]
            std_likelihood[idx] = np.sqrt(1 / effective_weights_total_HadCM_new_1056ppm[idx])
        else:
            # If there are no data points for this bin, set the likelihood to NaN
            mu_likelihood[idx] = np.nan
            std_likelihood[idx] = np.nan
        print(f"  Bin {bin_idx + 1}:")
        print(f"    Weighted Average: {mu_likelihood[idx]}")
        print(f"    Aggregated Uncertainty: {std_likelihood[idx]}")
        print(f"    Number of Data Points: {n_update_HadCM_new_1056ppm[idx]}")
    print()

print("Original Prior Mean SST-D47 monthly:\n", mu_prior_HadCM_new_1056ppm_SST_D47_monthly_original)
print("Original Prior Standard Deviation SST-D47 monthly:\n", np.sqrt(np.diag(cov_prior_HadCM_new_1056ppm_SST_D47_monthly_original)))
print("Updated Posterior Mean SST-D47 monthly:\n", mu_post_HadCM_new_1056ppm_SST_D47)
print("Updated Posterior Standard Deviation SST-D47 monthly:\n", np.sqrt(np.diag(cov_post_HadCM_new_1056ppm_SST_D47)))
print("Original Prior Mean SAT-D47 monthly:\n", mu_prior_HadCM_new_1056ppm_SAT_monthly_original)
print("Original Prior Standard Deviation SAT-D47 monthly:\n", np.sqrt(np.diag(cov_prior_HadCM_new_1056ppm_SAT_monthly_original)))
print("Updated Posterior Mean SAT-D47 monthly:\n", mu_post_HadCM_new_1056ppm_SAT_D47)
print("Updated Posterior Standard Deviation SAT-D47 monthly:\n", np.sqrt(np.diag(cov_post_HadCM_new_1056ppm_SAT_D47)))
print("Original Prior Mean d18Oc monthly:\n", mu_prior_HadCM_new_1056ppm_d18Oc_monthly_original)
print("Original Prior Standard Deviation d18Oc monthly:\n", np.sqrt(np.diag(cov_prior_HadCM_new_1056ppm_d18Oc_monthly_original)))
print("Updated Posterior Mean d18Oc monthly:\n", mu_post_HadCM_new_1056ppm_d18Oc)
print("Updated Posterior Standard Deviation d18Oc monthly:\n", np.sqrt(np.diag(cov_post_HadCM_new_1056ppm_d18Oc)))
print("Original Prior Mean precipitation monthly:\n", mu_prior_HadCM_new_1056ppm_precip_monthly_original)
print("Original Prior Standard Deviation precipitation monthly:\n", np.sqrt(np.diag(cov_prior_HadCM_new_1056ppm_precip_monthly_original)))
print("Updated Posterior Mean precipitation monthly:\n", mu_post_HadCM_new_1056ppm_precip)
print("Updated Posterior Standard Deviation precipitation monthly:\n", np.sqrt(np.diag(cov_post_HadCM_new_1056ppm_precip)))
Likelihood statistics:
Results for variable: D47_mean
  Bin 1:
    Weighted Average: 0.6315000000000001
    Aggregated Uncertainty: 0.0145
    Number of Data Points: 1.0
  Bin 2:
    Weighted Average: 0.5964285714285714
    Aggregated Uncertainty: 0.01096096971726759
    Number of Data Points: 1.0
  Bin 3:
    Weighted Average: 0.6065
    Aggregated Uncertainty: 0.010253048327204941
    Number of Data Points: 1.0
  Bin 4:
    Weighted Average: nan
    Aggregated Uncertainty: nan
    Number of Data Points: 0.0
  Bin 5:
    Weighted Average: 0.5749687499999999
    Aggregated Uncertainty: 0.0051265241636024705
    Number of Data Points: 1.0
  Bin 6:
    Weighted Average: 0.5925625
    Aggregated Uncertainty: 0.00725
    Number of Data Points: 1.0
  Bin 7:
    Weighted Average: 0.5888260869565218
    Aggregated Uncertainty: 0.004275816728492018
    Number of Data Points: 1.0
  Bin 8:
    Weighted Average: nan
    Aggregated Uncertainty: nan
    Number of Data Points: 0.0
  Bin 9:
    Weighted Average: 0.5830000000000001
    Aggregated Uncertainty: 0.004973458969132757
    Number of Data Points: 1.0
  Bin 10:
    Weighted Average: nan
    Aggregated Uncertainty: nan
    Number of Data Points: 0.0
  Bin 11:
    Weighted Average: 0.594
    Aggregated Uncertainty: 0.011839200423452026
    Number of Data Points: 1.0
  Bin 12:
    Weighted Average: 0.5921333333333333
    Aggregated Uncertainty: 0.007487767802667672
    Number of Data Points: 1.0

Results for variable: d18O
  Bin 1:
    Weighted Average: 0.016000000000000014
    Aggregated Uncertainty: 0.0447213595499958
    Number of Data Points: 1.0
  Bin 2:
    Weighted Average: 0.10700000000000001
    Aggregated Uncertainty: 0.0316227766016838
    Number of Data Points: 1.0
  Bin 3:
    Weighted Average: -0.22615384615384615
    Aggregated Uncertainty: 0.02773500981126146
    Number of Data Points: 1.0
  Bin 4:
    Weighted Average: -0.5469999999999999
    Aggregated Uncertainty: 0.01414213562373095
    Number of Data Points: 1.0
  Bin 5:
    Weighted Average: -1.2017647058823526
    Aggregated Uncertainty: 0.009166984970282115
    Number of Data Points: 1.0
  Bin 6:
    Weighted Average: -1.6498290598290601
    Aggregated Uncertainty: 0.009245003270420488
    Number of Data Points: 1.0
  Bin 7:
    Weighted Average: -2.0610810810810816
    Aggregated Uncertainty: 0.009491579957524992
    Number of Data Points: 1.0
  Bin 8:
    Weighted Average: -1.7621904761904763
    Aggregated Uncertainty: 0.009759000729485335
    Number of Data Points: 1.0
  Bin 9:
    Weighted Average: -1.3562711864406782
    Aggregated Uncertainty: 0.009205746178983237
    Number of Data Points: 1.0
  Bin 10:
    Weighted Average: -0.5620833333333334
    Aggregated Uncertainty: 0.014433756729740647
    Number of Data Points: 1.0
  Bin 11:
    Weighted Average: -0.06419354838709676
    Aggregated Uncertainty: 0.017960530202677495
    Number of Data Points: 1.0
  Bin 12:
    Weighted Average: -0.162
    Aggregated Uncertainty: 0.0223606797749979
    Number of Data Points: 1.0

Original Prior Mean SST-D47 monthly:
 [0.61178805 0.61408643 0.61450653 0.61183965 0.60351899 0.58890726
 0.57896879 0.57614968 0.58012824 0.58940847 0.60010733 0.60731336]
Original Prior Standard Deviation SST-D47 monthly:
 [0.00950473 0.00991746 0.00975143 0.00855046 0.00601008 0.00264934
 0.001987   0.00193393 0.00336092 0.00555588 0.00726523 0.00854462]
Updated Posterior Mean SST-D47 monthly:
 [0.6059617  0.60965206 0.61117591 0.61183965 0.60699861 0.5936751
 0.58146936 0.57614968 0.58006555 0.58940847 0.59723649 0.60229133]
Updated Posterior Standard Deviation SST-D47 monthly:
 [7.37920109e-04 6.45206398e-04 4.07501316e-04 5.76226444e-10
 4.23070544e-04 6.43039061e-04 3.00159791e-04 4.11590317e-11
 1.45475116e-04 8.23180635e-10 2.96105409e-04 5.37685293e-04]
Original Prior Mean SAT-D47 monthly:
 [16.54376119 16.33315684 16.66519572 18.1570933  21.33070018 26.04470978
 29.27867788 30.05242564 28.38777822 24.68946991 20.37269491 17.89802958]
Original Prior Standard Deviation SAT-D47 monthly:
 [3.1136452  2.87241146 2.6653854  2.24775679 1.63278962 0.69198219
 0.47930615 0.56291876 1.14972847 2.03401859 2.74423138 3.08483859]
Updated Posterior Mean SAT-D47 monthly:
 [0.60433745 0.60479057 0.60292906 0.59708906 0.5891163  0.58062087
 0.57349845 0.5721597  0.57390406 0.58219882 0.59359416 0.60009983]
Updated Posterior Standard Deviation SAT-D47 monthly:
 [0.00081662 0.00080777 0.00081614 0.00093723 0.00099199 0.00075654
 0.00052592 0.00035384 0.00049973 0.00063044 0.00078469 0.00084532]
Original Prior Mean d18Oc monthly:
 [ 0.89938202  1.06227796  1.09074434  0.89304546  0.26814927 -0.85652748
 -1.63310083 -1.85641729 -1.52480304 -0.78486291  0.03877691  0.57421982]
Original Prior Standard Deviation d18Oc monthly:
 [0.58354349 0.60848538 0.59658837 0.51493414 0.33894432 0.09898967
 0.16122308 0.13822702 0.15000845 0.32013947 0.4397222  0.52235491]
Updated Posterior Mean d18Oc monthly:
 [ 0.15197295  0.26100485  0.21607202 -0.05770915 -0.54535977 -1.29778997
 -1.86136787 -1.92176705 -1.82082829 -1.29126878 -0.5693999  -0.13270156]
Updated Posterior Standard Deviation d18Oc monthly:
 [0.04367811 0.04251691 0.04035924 0.04344383 0.0457741  0.04436709
 0.04601354 0.04063306 0.02606902 0.03079696 0.04333981 0.04545931]
Original Prior Mean precipitation monthly:
 [4.56713648 3.91851193 2.74238199 2.21756103 2.6688204  2.25554827
 2.59721839 3.43563859 3.46278601 4.34280869 4.56264103 4.84894508]
Original Prior Standard Deviation precipitation monthly:
 [0.85407461 0.70612807 0.50598617 0.43407756 1.00076624 1.0245456
 1.00411221 1.11605905 0.828573   1.1991117  0.95570044 1.00690122]
Updated Posterior Mean precipitation monthly:
 [8.59834819 7.40964913 5.08979493 3.61994327 3.35145921 1.66313621
 2.59151062 5.22696667 7.05816581 7.44125433 8.5142906  9.51385992]
Updated Posterior Standard Deviation precipitation monthly:
 [0.57092592 0.46340285 0.32062732 0.25540271 0.3659027  0.41046382
 0.42360275 0.57144701 0.62346658 0.60559179 0.56482241 0.59676163]

Update monthly priors from HadCM (old) 2x preindustrial pCO2 with aggregated data¶

  • Data and model outcomes aggregated in 12 months
  • No sclero-dating uncertainty
  • D47 Data aggregated per specimen and per month
In [70]:
# Apply Kalman function to update the prior with monthly data including updating the prec estimates
# Update the monthly D47 and prec prior with all measurements using block updating
monthly_aggregated_data = {} # Keep track of datapoints per season
n_update_HadCM_old_2PIC = np.concatenate([mu_prior_HadCM_old_2PIC_SST_D47_monthly * 0, mu_prior_HadCM_old_2PIC_d18Oc_monthly * 0]) # Vector to store sample size per season for confidence interval plotting
weighted_sum_HadCM_old_2PIC = np.concatenate([mu_prior_HadCM_old_2PIC_SST_D47_monthly * 0, mu_prior_HadCM_old_2PIC_d18Oc_monthly * 0]) # Vector to store mean temperature per season for confidence interval plotting
effective_weights_total_HadCM_old_2PIC = np.concatenate([mu_prior_HadCM_old_2PIC_SST_D47_monthly * 0, mu_prior_HadCM_old_2PIC_d18Oc_monthly * 0]) # Vector to store temperature uncertainty per season for confidence interval plotting
mu_likelihood = np.concatenate([mu_prior_HadCM_old_2PIC_SST_D47_monthly * 0, mu_prior_HadCM_old_2PIC_d18Oc_monthly * 0]) # Vector to store mean temperature per season for confidence interval plotting
std_likelihood = np.concatenate([mu_prior_HadCM_old_2PIC_SST_D47_monthly * 0, mu_prior_HadCM_old_2PIC_d18Oc_monthly * 0]) # Vector to store temperature uncertainty per season for confidence interval plotting
var_names = ["D47_mean", "d18O"] # List of variable names which are updated
var_SD_names = ["D47_SD", "d18O_SD"] # List of names of variable uncertainties which are updated

# Update the prior with monthly data using the Kalman filter in block updating form
mu_post_HadCM_old_2PIC, cov_post_HadCM_old_2PIC = kalman_update_block(
    mu_prior_HadCM_old_2PIC_monthly_combined,
    cov_prior_HadCM_old_2PIC_monthly_combined,
    Z,
    R,
    H
)

# Extract the updated mean values from the combined state vector
mu_post_HadCM_old_2PIC_SST_D47 = mu_post_HadCM_old_2PIC[:len(mu_prior_HadCM_old_2PIC_SST_D47_monthly)]
mu_post_HadCM_old_2PIC_SAT_D47 = mu_post_HadCM_old_2PIC[len(mu_prior_HadCM_old_2PIC_SST_D47_monthly):2*len(mu_prior_HadCM_old_2PIC_SST_D47_monthly)]
mu_post_HadCM_old_2PIC_d18Oc = mu_post_HadCM_old_2PIC[2*len(mu_prior_HadCM_old_2PIC_SST_D47_monthly):3*len(mu_prior_HadCM_old_2PIC_SST_D47_monthly)]
mu_post_HadCM_old_2PIC_precip = mu_post_HadCM_old_2PIC[3*len(mu_prior_HadCM_old_2PIC_d18Oc_monthly):]

# Extract the updated covariance matrices from the combined covariance matrix
cov_post_HadCM_old_2PIC_SST_D47 = cov_post_HadCM_old_2PIC[:len(mu_prior_HadCM_old_2PIC_SST_D47_monthly), :len(mu_prior_HadCM_old_2PIC_SST_D47_monthly)]
cov_post_HadCM_old_2PIC_SAT_D47 = cov_post_HadCM_old_2PIC[len(mu_prior_HadCM_old_2PIC_SST_D47_monthly):2*len(mu_prior_HadCM_old_2PIC_SST_D47_monthly), len(mu_prior_HadCM_old_2PIC_SST_D47_monthly):2*len(mu_prior_HadCM_old_2PIC_SST_D47_monthly)]
cov_post_HadCM_old_2PIC_d18Oc = cov_post_HadCM_old_2PIC[2*len(mu_prior_HadCM_old_2PIC_SST_D47_monthly):3*len(mu_prior_HadCM_old_2PIC_SST_D47_monthly), 2*len(mu_prior_HadCM_old_2PIC_SST_D47_monthly):3*len(mu_prior_HadCM_old_2PIC_SST_D47_monthly)]
cov_post_HadCM_old_2PIC_precip = cov_post_HadCM_old_2PIC[3*len(mu_prior_HadCM_old_2PIC_d18Oc_monthly):, 3*len(mu_prior_HadCM_old_2PIC_d18Oc_monthly):]

for measurement in Lutetian_data_monthly_aggregated_dict: # Loop over measurements    
    # Track and update likelihood statistics
    weighted_sum_HadCM_old_2PIC, effective_weights_total_HadCM_old_2PIC, n_update_HadCM_old_2PIC, monthly_aggregated_data = likelihood_statistics_multi(
        weighted_sum_HadCM_old_2PIC,
        effective_weights_total_HadCM_old_2PIC,
        n_update_HadCM_old_2PIC,
        monthly_aggregated_data,
        measurement,
        timestamp = "month_score",
        timestamp_sd = "Month_err",
        Variable_names = var_names,
        Variable_names_SDs = var_SD_names
    )

# Normalize the weighted_sum_HadCM_old_2PIC to obtain weighted mean
# Calculate inverse square root of the effective_weights_total_HadCM_old_2PIC to contain the weighted standard deviation
# Print likelihood statistics
print("Likelihood statistics:")
num_vars = len(var_names)  # number of variables (e.g., D47, d18O)
num_bins_monthly = int(len(weighted_sum_HadCM_old_2PIC) / num_vars)

for var_idx, var_name in enumerate(var_names):
    print(f"Results for variable: {var_name}")
    for bin_idx in range(num_bins_monthly):
        idx = var_idx * num_bins_monthly + bin_idx
        if effective_weights_total_HadCM_old_2PIC[idx] is not None and effective_weights_total_HadCM_old_2PIC[idx] != 0:
            mu_likelihood[idx] = weighted_sum_HadCM_old_2PIC[idx] / effective_weights_total_HadCM_old_2PIC[idx]
            std_likelihood[idx] = np.sqrt(1 / effective_weights_total_HadCM_old_2PIC[idx])
        else:
            # If there are no data points for this bin, set the likelihood to NaN
            mu_likelihood[idx] = np.nan
            std_likelihood[idx] = np.nan
        print(f"  Bin {bin_idx + 1}:")
        print(f"    Weighted Average: {mu_likelihood[idx]}")
        print(f"    Aggregated Uncertainty: {std_likelihood[idx]}")
        print(f"    Number of Data Points: {n_update_HadCM_old_2PIC[idx]}")
    print()

print("Original Prior Mean SST-D47 monthly:\n", mu_prior_HadCM_old_2PIC_SST_D47_monthly_original)
print("Original Prior Standard Deviation SST-D47 monthly:\n", np.sqrt(np.diag(cov_prior_HadCM_old_2PIC_SST_D47_monthly_original)))
print("Updated Posterior Mean SST-D47 monthly:\n", mu_post_HadCM_old_2PIC_SST_D47)
print("Updated Posterior Standard Deviation SST-D47 monthly:\n", np.sqrt(np.diag(cov_post_HadCM_old_2PIC_SST_D47)))
print("Original Prior Mean SAT-D47 monthly:\n", mu_prior_HadCM_old_2PIC_SAT_monthly_original)
print("Original Prior Standard Deviation SAT-D47 monthly:\n", np.sqrt(np.diag(cov_prior_HadCM_old_2PIC_SAT_monthly_original)))
print("Updated Posterior Mean SAT-D47 monthly:\n", mu_post_HadCM_old_2PIC_SAT_D47)
print("Updated Posterior Standard Deviation SAT-D47 monthly:\n", np.sqrt(np.diag(cov_post_HadCM_old_2PIC_SAT_D47)))
print("Original Prior Mean d18Oc monthly:\n", mu_prior_HadCM_old_2PIC_d18Oc_monthly_original)
print("Original Prior Standard Deviation d18Oc monthly:\n", np.sqrt(np.diag(cov_prior_HadCM_old_2PIC_d18Oc_monthly_original)))
print("Updated Posterior Mean d18Oc monthly:\n", mu_post_HadCM_old_2PIC_d18Oc)
print("Updated Posterior Standard Deviation d18Oc monthly:\n", np.sqrt(np.diag(cov_post_HadCM_old_2PIC_d18Oc)))
print("Original Prior Mean precipitation monthly:\n", mu_prior_HadCM_old_2PIC_precip_monthly_original)
print("Original Prior Standard Deviation precipitation monthly:\n", np.sqrt(np.diag(cov_prior_HadCM_old_2PIC_precip_monthly_original)))
print("Updated Posterior Mean precipitation monthly:\n", mu_post_HadCM_old_2PIC_precip)
print("Updated Posterior Standard Deviation precipitation monthly:\n", np.sqrt(np.diag(cov_post_HadCM_old_2PIC_precip)))
Likelihood statistics:
Results for variable: D47_mean
  Bin 1:
    Weighted Average: 0.6315000000000001
    Aggregated Uncertainty: 0.0145
    Number of Data Points: 1.0
  Bin 2:
    Weighted Average: 0.5964285714285714
    Aggregated Uncertainty: 0.01096096971726759
    Number of Data Points: 1.0
  Bin 3:
    Weighted Average: 0.6065
    Aggregated Uncertainty: 0.010253048327204941
    Number of Data Points: 1.0
  Bin 4:
    Weighted Average: nan
    Aggregated Uncertainty: nan
    Number of Data Points: 0.0
  Bin 5:
    Weighted Average: 0.5749687499999999
    Aggregated Uncertainty: 0.0051265241636024705
    Number of Data Points: 1.0
  Bin 6:
    Weighted Average: 0.5925625
    Aggregated Uncertainty: 0.00725
    Number of Data Points: 1.0
  Bin 7:
    Weighted Average: 0.5888260869565218
    Aggregated Uncertainty: 0.004275816728492018
    Number of Data Points: 1.0
  Bin 8:
    Weighted Average: nan
    Aggregated Uncertainty: nan
    Number of Data Points: 0.0
  Bin 9:
    Weighted Average: 0.5830000000000001
    Aggregated Uncertainty: 0.004973458969132757
    Number of Data Points: 1.0
  Bin 10:
    Weighted Average: nan
    Aggregated Uncertainty: nan
    Number of Data Points: 0.0
  Bin 11:
    Weighted Average: 0.594
    Aggregated Uncertainty: 0.011839200423452026
    Number of Data Points: 1.0
  Bin 12:
    Weighted Average: 0.5921333333333333
    Aggregated Uncertainty: 0.007487767802667672
    Number of Data Points: 1.0

Results for variable: d18O
  Bin 1:
    Weighted Average: 0.016000000000000014
    Aggregated Uncertainty: 0.0447213595499958
    Number of Data Points: 1.0
  Bin 2:
    Weighted Average: 0.10700000000000001
    Aggregated Uncertainty: 0.0316227766016838
    Number of Data Points: 1.0
  Bin 3:
    Weighted Average: -0.22615384615384615
    Aggregated Uncertainty: 0.02773500981126146
    Number of Data Points: 1.0
  Bin 4:
    Weighted Average: -0.5469999999999999
    Aggregated Uncertainty: 0.01414213562373095
    Number of Data Points: 1.0
  Bin 5:
    Weighted Average: -1.2017647058823526
    Aggregated Uncertainty: 0.009166984970282115
    Number of Data Points: 1.0
  Bin 6:
    Weighted Average: -1.6498290598290601
    Aggregated Uncertainty: 0.009245003270420488
    Number of Data Points: 1.0
  Bin 7:
    Weighted Average: -2.0610810810810816
    Aggregated Uncertainty: 0.009491579957524992
    Number of Data Points: 1.0
  Bin 8:
    Weighted Average: -1.7621904761904763
    Aggregated Uncertainty: 0.009759000729485335
    Number of Data Points: 1.0
  Bin 9:
    Weighted Average: -1.3562711864406782
    Aggregated Uncertainty: 0.009205746178983237
    Number of Data Points: 1.0
  Bin 10:
    Weighted Average: -0.5620833333333334
    Aggregated Uncertainty: 0.014433756729740647
    Number of Data Points: 1.0
  Bin 11:
    Weighted Average: -0.06419354838709676
    Aggregated Uncertainty: 0.017960530202677495
    Number of Data Points: 1.0
  Bin 12:
    Weighted Average: -0.162
    Aggregated Uncertainty: 0.0223606797749979
    Number of Data Points: 1.0

Original Prior Mean SST-D47 monthly:
 [0.60952059 0.61177987 0.61211207 0.60890818 0.59999147 0.58762014
 0.57910703 0.57497457 0.5767857  0.58612855 0.59672445 0.60499141]
Original Prior Standard Deviation SST-D47 monthly:
 [0.00730275 0.00751657 0.00756292 0.00688203 0.00519937 0.00330025
 0.00165647 0.00170597 0.00223992 0.00457919 0.0061014  0.00687984]
Updated Posterior Mean SST-D47 monthly:
 [0.60929279 0.61110217 0.61146843 0.60890818 0.60132146 0.59679646
 0.5913868  0.57497457 0.570493   0.58612855 0.59963663 0.60529398]
Updated Posterior Standard Deviation SST-D47 monthly:
 [4.06383364e-04 3.17817205e-04 2.03849021e-04 3.29272254e-10
 3.16315655e-04 7.34458148e-04 6.69732097e-04            nan
 3.03903741e-04 3.86105942e-10 2.61070761e-04 4.46781687e-04]
Original Prior Mean SAT-D47 monthly:
 [17.37342478 17.21628214 17.78856557 19.24039866 22.18971914 26.23706462
 29.33261007 30.70993194 29.73895416 26.07219594 21.69050496 18.52393239]
Original Prior Standard Deviation SAT-D47 monthly:
 [3.2114442  2.69102368 2.25082291 1.96523166 1.63807297 1.35401718
 0.73510388 0.49971448 0.91035189 1.98977278 2.90543435 3.37134836]
Updated Posterior Mean SAT-D47 monthly:
 [0.59961509 0.59806084 0.59560856 0.59335018 0.58767151 0.57412668
 0.56915225 0.57456599 0.5788128  0.58115739 0.59084795 0.59835057]
Updated Posterior Standard Deviation SAT-D47 monthly:
 [0.00141255 0.00136087 0.00132509 0.0012541  0.00116415 0.0010171
 0.00093373 0.00091888 0.00085299 0.00101592 0.00124689 0.001419  ]
Original Prior Mean d18Oc monthly:
 [ 2.610453    2.78266516  2.80531485  2.55561563  1.87962861  0.93728201
  0.28135718 -0.03614475  0.1034491   0.83319401  1.64799416  2.27215511]
Original Prior Standard Deviation d18Oc monthly:
 [0.36157545 0.37407513 0.37312685 0.32006347 0.21320302 0.15150899
 0.19818414 0.24130267 0.10970853 0.19072319 0.29013312 0.33416273]
Updated Posterior Mean d18Oc monthly:
 [ 0.10466442  0.18408074  0.15635633  0.02406903 -0.41678584 -1.41772702
 -1.76512541 -1.35428154 -1.1531825  -1.12463334 -0.6287255  -0.13126015]
Updated Posterior Standard Deviation d18Oc monthly:
 [0.04366004 0.04294683 0.04246724 0.04064485 0.04176134 0.05359773
 0.05593455 0.05003228 0.03412996 0.03322553 0.0375173  0.04319486]
Original Prior Mean precipitation monthly:
 [4.51414761 2.96477545 2.0466914  1.70405398 1.499306   0.98548384
 1.2141631  1.94227658 3.96484522 4.89490475 5.10539876 4.79175341]
Original Prior Standard Deviation precipitation monthly:
 [0.54851291 0.54980863 0.52847315 0.61988324 0.67752496 0.34351868
 0.40517783 0.93230212 0.90520864 0.74675508 0.64169083 0.55874858]
Updated Posterior Mean precipitation monthly:
 [ 5.78186312  2.53759874  2.42827759  3.3392642   4.79783349  3.08769232
 -0.2446832  -1.10487115  5.96112349  8.00533232  2.18892769  5.62862659]
Updated Posterior Standard Deviation precipitation monthly:
 [0.36594123 0.20462568 0.19978116 0.24788844 0.32308452 0.17565873
 0.28027528 0.46830502 0.61994237 0.63269722 0.43719639 0.40715268]
C:\Users\nwi213\AppData\Local\Temp\ipykernel_4724\2718528581.py:74: RuntimeWarning: invalid value encountered in sqrt
  print("Updated Posterior Standard Deviation SST-D47 monthly:\n", np.sqrt(np.diag(cov_post_HadCM_old_2PIC_SST_D47)))

Update monthly priors from HadCM (old) 4x preindustrial pCO2 with aggregated data¶

  • Data and model outcomes aggregated in 12 months
  • No sclero-dating uncertainty
  • D47 Data aggregated per specimen and per month
In [71]:
# Apply Kalman function to update the prior with monthly data including updating the prec estimates
# Update the monthly D47 and prec prior with all measurements using block updating
monthly_aggregated_data = {} # Keep track of datapoints per season
n_update_HadCM_old_4PIC = np.concatenate([mu_prior_HadCM_old_4PIC_SST_D47_monthly * 0, mu_prior_HadCM_old_4PIC_d18Oc_monthly * 0]) # Vector to store sample size per season for confidence interval plotting
weighted_sum_HadCM_old_4PIC = np.concatenate([mu_prior_HadCM_old_4PIC_SST_D47_monthly * 0, mu_prior_HadCM_old_4PIC_d18Oc_monthly * 0]) # Vector to store mean temperature per season for confidence interval plotting
effective_weights_total_HadCM_old_4PIC = np.concatenate([mu_prior_HadCM_old_4PIC_SST_D47_monthly * 0, mu_prior_HadCM_old_4PIC_d18Oc_monthly * 0]) # Vector to store temperature uncertainty per season for confidence interval plotting
mu_likelihood = np.concatenate([mu_prior_HadCM_old_4PIC_SST_D47_monthly * 0, mu_prior_HadCM_old_4PIC_d18Oc_monthly * 0]) # Vector to store mean temperature per season for confidence interval plotting
std_likelihood = np.concatenate([mu_prior_HadCM_old_4PIC_SST_D47_monthly * 0, mu_prior_HadCM_old_4PIC_d18Oc_monthly * 0]) # Vector to store temperature uncertainty per season for confidence interval plotting
var_names = ["D47_mean", "d18O"] # List of variable names which are updated
var_SD_names = ["D47_SD", "d18O_SD"] # List of names of variable uncertainties which are updated

# Update the prior with monthly data using the Kalman filter in block updating form
mu_post_HadCM_old_4PIC, cov_post_HadCM_old_4PIC = kalman_update_block(
    mu_prior_HadCM_old_4PIC_monthly_combined,
    cov_prior_HadCM_old_4PIC_monthly_combined,
    Z,
    R,
    H
)

# Extract the updated mean values from the combined state vector
mu_post_HadCM_old_4PIC_SST_D47 = mu_post_HadCM_old_4PIC[:len(mu_prior_HadCM_old_4PIC_SST_D47_monthly)]
mu_post_HadCM_old_4PIC_SAT_D47 = mu_post_HadCM_old_4PIC[len(mu_prior_HadCM_old_4PIC_SST_D47_monthly):2*len(mu_prior_HadCM_old_4PIC_SST_D47_monthly)]
mu_post_HadCM_old_4PIC_d18Oc = mu_post_HadCM_old_4PIC[2*len(mu_prior_HadCM_old_4PIC_SST_D47_monthly):3*len(mu_prior_HadCM_old_4PIC_SST_D47_monthly)]
mu_post_HadCM_old_4PIC_precip = mu_post_HadCM_old_4PIC[3*len(mu_prior_HadCM_old_4PIC_d18Oc_monthly):]

# Extract the updated covariance matrices from the combined covariance matrix
cov_post_HadCM_old_4PIC_SST_D47 = cov_post_HadCM_old_4PIC[:len(mu_prior_HadCM_old_4PIC_SST_D47_monthly), :len(mu_prior_HadCM_old_4PIC_SST_D47_monthly)]
cov_post_HadCM_old_4PIC_SAT_D47 = cov_post_HadCM_old_4PIC[len(mu_prior_HadCM_old_4PIC_SST_D47_monthly):2*len(mu_prior_HadCM_old_4PIC_SST_D47_monthly), len(mu_prior_HadCM_old_4PIC_SST_D47_monthly):2*len(mu_prior_HadCM_old_4PIC_SST_D47_monthly)]
cov_post_HadCM_old_4PIC_d18Oc = cov_post_HadCM_old_4PIC[2*len(mu_prior_HadCM_old_4PIC_SST_D47_monthly):3*len(mu_prior_HadCM_old_4PIC_SST_D47_monthly), 2*len(mu_prior_HadCM_old_4PIC_SST_D47_monthly):3*len(mu_prior_HadCM_old_4PIC_SST_D47_monthly)]
cov_post_HadCM_old_4PIC_precip = cov_post_HadCM_old_4PIC[3*len(mu_prior_HadCM_old_4PIC_d18Oc_monthly):, 3*len(mu_prior_HadCM_old_4PIC_d18Oc_monthly):]

for measurement in Lutetian_data_monthly_aggregated_dict: # Loop over measurements    
    # Track and update likelihood statistics
    weighted_sum_HadCM_old_4PIC, effective_weights_total_HadCM_old_4PIC, n_update_HadCM_old_4PIC, monthly_aggregated_data = likelihood_statistics_multi(
        weighted_sum_HadCM_old_4PIC,
        effective_weights_total_HadCM_old_4PIC,
        n_update_HadCM_old_4PIC,
        monthly_aggregated_data,
        measurement,
        timestamp = "month_score",
        timestamp_sd = "Month_err",
        Variable_names = var_names,
        Variable_names_SDs = var_SD_names
    )

# Normalize the weighted_sum_HadCM_old_4PIC to obtain weighted mean
# Calculate inverse square root of the effective_weights_total_HadCM_old_4PIC to contain the weighted standard deviation
# Print likelihood statistics
print("Likelihood statistics:")
num_vars = len(var_names)  # number of variables (e.g., D47, d18O)
num_bins_monthly = int(len(weighted_sum_HadCM_old_4PIC) / num_vars)

for var_idx, var_name in enumerate(var_names):
    print(f"Results for variable: {var_name}")
    for bin_idx in range(num_bins_monthly):
        idx = var_idx * num_bins_monthly + bin_idx
        if effective_weights_total_HadCM_old_4PIC[idx] is not None and effective_weights_total_HadCM_old_4PIC[idx] != 0:
            mu_likelihood[idx] = weighted_sum_HadCM_old_4PIC[idx] / effective_weights_total_HadCM_old_4PIC[idx]
            std_likelihood[idx] = np.sqrt(1 / effective_weights_total_HadCM_old_4PIC[idx])
        else:
            # If there are no data points for this bin, set the likelihood to NaN
            mu_likelihood[idx] = np.nan
            std_likelihood[idx] = np.nan
        print(f"  Bin {bin_idx + 1}:")
        print(f"    Weighted Average: {mu_likelihood[idx]}")
        print(f"    Aggregated Uncertainty: {std_likelihood[idx]}")
        print(f"    Number of Data Points: {n_update_HadCM_old_4PIC[idx]}")
    print()

print("Original Prior Mean SST-D47 monthly:\n", mu_prior_HadCM_old_4PIC_SST_D47_monthly_original)
print("Original Prior Standard Deviation SST-D47 monthly:\n", np.sqrt(np.diag(cov_prior_HadCM_old_4PIC_SST_D47_monthly_original)))
print("Updated Posterior Mean SST-D47 monthly:\n", mu_post_HadCM_old_4PIC_SST_D47)
print("Updated Posterior Standard Deviation SST-D47 monthly:\n", np.sqrt(np.diag(cov_post_HadCM_old_4PIC_SST_D47)))
print("Original Prior Mean SAT-D47 monthly:\n", mu_prior_HadCM_old_4PIC_SAT_monthly_original)
print("Original Prior Standard Deviation SAT-D47 monthly:\n", np.sqrt(np.diag(cov_prior_HadCM_old_4PIC_SAT_monthly_original)))
print("Updated Posterior Mean SAT-D47 monthly:\n", mu_post_HadCM_old_4PIC_SAT_D47)
print("Updated Posterior Standard Deviation SAT-D47 monthly:\n", np.sqrt(np.diag(cov_post_HadCM_old_4PIC_SAT_D47)))
print("Original Prior Mean d18Oc monthly:\n", mu_prior_HadCM_old_4PIC_d18Oc_monthly_original)
print("Original Prior Standard Deviation d18Oc monthly:\n", np.sqrt(np.diag(cov_prior_HadCM_old_4PIC_d18Oc_monthly_original)))
print("Updated Posterior Mean d18Oc monthly:\n", mu_post_HadCM_old_4PIC_d18Oc)
print("Updated Posterior Standard Deviation d18Oc monthly:\n", np.sqrt(np.diag(cov_post_HadCM_old_4PIC_d18Oc)))
print("Original Prior Mean precipitation monthly:\n", mu_prior_HadCM_old_4PIC_precip_monthly_original)
print("Original Prior Standard Deviation precipitation monthly:\n", np.sqrt(np.diag(cov_prior_HadCM_old_4PIC_precip_monthly_original)))
print("Updated Posterior Mean precipitation monthly:\n", mu_post_HadCM_old_4PIC_precip)
print("Updated Posterior Standard Deviation precipitation monthly:\n", np.sqrt(np.diag(cov_post_HadCM_old_4PIC_precip)))
Likelihood statistics:
Results for variable: D47_mean
  Bin 1:
    Weighted Average: 0.6315000000000001
    Aggregated Uncertainty: 0.0145
    Number of Data Points: 1.0
  Bin 2:
    Weighted Average: 0.5964285714285714
    Aggregated Uncertainty: 0.01096096971726759
    Number of Data Points: 1.0
  Bin 3:
    Weighted Average: 0.6065
    Aggregated Uncertainty: 0.010253048327204941
    Number of Data Points: 1.0
  Bin 4:
    Weighted Average: nan
    Aggregated Uncertainty: nan
    Number of Data Points: 0.0
  Bin 5:
    Weighted Average: 0.5749687499999999
    Aggregated Uncertainty: 0.0051265241636024705
    Number of Data Points: 1.0
  Bin 6:
    Weighted Average: 0.5925625
    Aggregated Uncertainty: 0.00725
    Number of Data Points: 1.0
  Bin 7:
    Weighted Average: 0.5888260869565218
    Aggregated Uncertainty: 0.004275816728492018
    Number of Data Points: 1.0
  Bin 8:
    Weighted Average: nan
    Aggregated Uncertainty: nan
    Number of Data Points: 0.0
  Bin 9:
    Weighted Average: 0.5830000000000001
    Aggregated Uncertainty: 0.004973458969132757
    Number of Data Points: 1.0
  Bin 10:
    Weighted Average: nan
    Aggregated Uncertainty: nan
    Number of Data Points: 0.0
  Bin 11:
    Weighted Average: 0.594
    Aggregated Uncertainty: 0.011839200423452026
    Number of Data Points: 1.0
  Bin 12:
    Weighted Average: 0.5921333333333333
    Aggregated Uncertainty: 0.007487767802667672
    Number of Data Points: 1.0

Results for variable: d18O
  Bin 1:
    Weighted Average: 0.016000000000000014
    Aggregated Uncertainty: 0.0447213595499958
    Number of Data Points: 1.0
  Bin 2:
    Weighted Average: 0.10700000000000001
    Aggregated Uncertainty: 0.0316227766016838
    Number of Data Points: 1.0
  Bin 3:
    Weighted Average: -0.22615384615384615
    Aggregated Uncertainty: 0.02773500981126146
    Number of Data Points: 1.0
  Bin 4:
    Weighted Average: -0.5469999999999999
    Aggregated Uncertainty: 0.01414213562373095
    Number of Data Points: 1.0
  Bin 5:
    Weighted Average: -1.2017647058823526
    Aggregated Uncertainty: 0.009166984970282115
    Number of Data Points: 1.0
  Bin 6:
    Weighted Average: -1.6498290598290601
    Aggregated Uncertainty: 0.009245003270420488
    Number of Data Points: 1.0
  Bin 7:
    Weighted Average: -2.0610810810810816
    Aggregated Uncertainty: 0.009491579957524992
    Number of Data Points: 1.0
  Bin 8:
    Weighted Average: -1.7621904761904763
    Aggregated Uncertainty: 0.009759000729485335
    Number of Data Points: 1.0
  Bin 9:
    Weighted Average: -1.3562711864406782
    Aggregated Uncertainty: 0.009205746178983237
    Number of Data Points: 1.0
  Bin 10:
    Weighted Average: -0.5620833333333334
    Aggregated Uncertainty: 0.014433756729740647
    Number of Data Points: 1.0
  Bin 11:
    Weighted Average: -0.06419354838709676
    Aggregated Uncertainty: 0.017960530202677495
    Number of Data Points: 1.0
  Bin 12:
    Weighted Average: -0.162
    Aggregated Uncertainty: 0.0223606797749979
    Number of Data Points: 1.0

Original Prior Mean SST-D47 monthly:
 [0.60952059 0.61177987 0.61211207 0.60890818 0.59999147 0.58762014
 0.57910703 0.57497457 0.5767857  0.58612855 0.59672445 0.60499141]
Original Prior Standard Deviation SST-D47 monthly:
 [0.00730275 0.00751657 0.00756292 0.00688203 0.00519937 0.00330025
 0.00165647 0.00170597 0.00223992 0.00457919 0.0061014  0.00687984]
Updated Posterior Mean SST-D47 monthly:
 [0.60929279 0.61110217 0.61146843 0.60890818 0.60132146 0.59679646
 0.5913868  0.57497457 0.570493   0.58612855 0.59963663 0.60529398]
Updated Posterior Standard Deviation SST-D47 monthly:
 [4.06383364e-04 3.17817205e-04 2.03849021e-04 3.29272254e-10
 3.16315655e-04 7.34458148e-04 6.69732097e-04            nan
 3.03903741e-04 3.86105942e-10 2.61070761e-04 4.46781687e-04]
Original Prior Mean SAT-D47 monthly:
 [17.37342478 17.21628214 17.78856557 19.24039866 22.18971914 26.23706462
 29.33261007 30.70993194 29.73895416 26.07219594 21.69050496 18.52393239]
Original Prior Standard Deviation SAT-D47 monthly:
 [3.2114442  2.69102368 2.25082291 1.96523166 1.63807297 1.35401718
 0.73510388 0.49971448 0.91035189 1.98977278 2.90543435 3.37134836]
Updated Posterior Mean SAT-D47 monthly:
 [0.59961509 0.59806084 0.59560856 0.59335018 0.58767151 0.57412668
 0.56915225 0.57456599 0.5788128  0.58115739 0.59084795 0.59835057]
Updated Posterior Standard Deviation SAT-D47 monthly:
 [0.00141255 0.00136087 0.00132509 0.0012541  0.00116415 0.0010171
 0.00093373 0.00091888 0.00085299 0.00101592 0.00124689 0.001419  ]
Original Prior Mean d18Oc monthly:
 [ 2.610453    2.78266516  2.80531485  2.55561563  1.87962861  0.93728201
  0.28135718 -0.03614475  0.1034491   0.83319401  1.64799416  2.27215511]
Original Prior Standard Deviation d18Oc monthly:
 [0.36157545 0.37407513 0.37312685 0.32006347 0.21320302 0.15150899
 0.19818414 0.24130267 0.10970853 0.19072319 0.29013312 0.33416273]
Updated Posterior Mean d18Oc monthly:
 [ 0.10466442  0.18408074  0.15635633  0.02406903 -0.41678584 -1.41772702
 -1.76512541 -1.35428154 -1.1531825  -1.12463334 -0.6287255  -0.13126015]
Updated Posterior Standard Deviation d18Oc monthly:
 [0.04366004 0.04294683 0.04246724 0.04064485 0.04176134 0.05359773
 0.05593455 0.05003228 0.03412996 0.03322553 0.0375173  0.04319486]
Original Prior Mean precipitation monthly:
 [4.51414761 2.96477545 2.0466914  1.70405398 1.499306   0.98548384
 1.2141631  1.94227658 3.96484522 4.89490475 5.10539876 4.79175341]
Original Prior Standard Deviation precipitation monthly:
 [0.54851291 0.54980863 0.52847315 0.61988324 0.67752496 0.34351868
 0.40517783 0.93230212 0.90520864 0.74675508 0.64169083 0.55874858]
Updated Posterior Mean precipitation monthly:
 [ 5.78186312  2.53759874  2.42827759  3.3392642   4.79783349  3.08769232
 -0.2446832  -1.10487115  5.96112349  8.00533232  2.18892769  5.62862659]
Updated Posterior Standard Deviation precipitation monthly:
 [0.36594123 0.20462568 0.19978116 0.24788844 0.32308452 0.17565873
 0.28027528 0.46830502 0.61994237 0.63269722 0.43719639 0.40715268]
C:\Users\nwi213\AppData\Local\Temp\ipykernel_4724\1681332670.py:74: RuntimeWarning: invalid value encountered in sqrt
  print("Updated Posterior Standard Deviation SST-D47 monthly:\n", np.sqrt(np.diag(cov_post_HadCM_old_4PIC_SST_D47)))

Plot monthly posteriors in D47 and d18Oc domain for both 2x and 4x preindustrial pCO2 scenarios¶

Start by calculating standard deviations and number of updates for different model scenarios¶

In [72]:
std_post_CESM_4PIC_SST_D47 = np.sqrt(np.diag(cov_post_CESM_4PIC_SST_D47))
std_post_CESM_2PIC_SST_D47 = np.sqrt(np.diag(cov_post_CESM_2PIC_SST_D47))
std_post_HadCM_new_1PIC_SST_D47 = np.sqrt(np.diag(cov_post_HadCM_new_1PIC_SST_D47))
std_post_HadCM_new_2PIC_SST_D47 = np.sqrt(np.diag(cov_post_HadCM_new_2PIC_SST_D47))
std_post_HadCM_new_1056ppm_SST_D47 = np.sqrt(np.diag(cov_post_HadCM_new_1056ppm_SST_D47))
std_post_HadCM_old_2PIC_SST_D47 = np.sqrt(np.diag(cov_post_HadCM_old_2PIC_SST_D47))
std_post_HadCM_old_4PIC_SST_D47 = np.sqrt(np.diag(cov_post_HadCM_old_4PIC_SST_D47))

std_post_CESM_4PIC_d18Oc = np.sqrt(np.diag(cov_post_CESM_4PIC_d18Oc))
std_post_CESM_2PIC_d18Oc = np.sqrt(np.diag(cov_post_CESM_2PIC_d18Oc))
std_post_HadCM_new_1PIC_d18Oc = np.sqrt(np.diag(cov_post_HadCM_new_1PIC_d18Oc))
std_post_HadCM_new_2PIC_d18Oc = np.sqrt(np.diag(cov_post_HadCM_new_2PIC_d18Oc))
std_post_HadCM_new_1056ppm_d18Oc = np.sqrt(np.diag(cov_post_HadCM_new_1056ppm_d18Oc))
std_post_HadCM_old_2PIC_d18Oc = np.sqrt(np.diag(cov_post_HadCM_old_2PIC_d18Oc))
std_post_HadCM_old_4PIC_d18Oc = np.sqrt(np.diag(cov_post_HadCM_old_4PIC_d18Oc))

std_prior_CESM_4PIC_SST_D47_monthly_original = np.sqrt(np.diag(cov_prior_CESM_4PIC_SST_D47_monthly_original))
std_prior_CESM_2PIC_SST_D47_monthly_original = np.sqrt(np.diag(cov_prior_CESM_2PIC_SST_D47_monthly_original))
std_prior_HadCM_new_1PIC_SST_D47_monthly_original = np.sqrt(np.diag(cov_prior_HadCM_new_1PIC_SST_D47_monthly_original))
std_prior_HadCM_new_2PIC_SST_D47_monthly_original = np.sqrt(np.diag(cov_prior_HadCM_new_2PIC_SST_D47_monthly_original))
std_prior_HadCM_new_1056ppm_SST_D47_monthly_original = np.sqrt(np.diag(cov_prior_HadCM_new_1056ppm_SST_D47_monthly_original))
std_prior_HadCM_old_2PIC_SST_D47_monthly_original = np.sqrt(np.diag(cov_prior_HadCM_old_2PIC_SST_D47_monthly_original))
std_prior_HadCM_old_4PIC_SST_D47_monthly_original = np.sqrt(np.diag(cov_prior_HadCM_old_4PIC_SST_D47_monthly_original))

std_prior_CESM_4PIC_d18Oc_monthly_original = np.sqrt(np.diag(cov_prior_CESM_4PIC_d18Oc_monthly_original))
std_prior_CESM_2PIC_d18Oc_monthly_original = np.sqrt(np.diag(cov_prior_CESM_2PIC_d18Oc_monthly_original))
std_prior_HadCM_new_1PIC_d18Oc_monthly_original = np.sqrt(np.diag(cov_prior_HadCM_new_1PIC_d18Oc_monthly_original))
std_prior_HadCM_new_2PIC_d18Oc_monthly_original = np.sqrt(np.diag(cov_prior_HadCM_new_2PIC_d18Oc_monthly_original))
std_prior_HadCM_new_1056ppm_d18Oc_monthly_original = np.sqrt(np.diag(cov_prior_HadCM_new_1056ppm_d18Oc_monthly_original))
std_prior_HadCM_old_2PIC_d18Oc_monthly_original = np.sqrt(np.diag(cov_prior_HadCM_old_2PIC_d18Oc_monthly_original))
std_prior_HadCM_old_4PIC_d18Oc_monthly_original = np.sqrt(np.diag(cov_prior_HadCM_old_4PIC_d18Oc_monthly_original))

var_start_D47_monthly = var_names.index("D47_mean") * num_bins_monthly # Determine the start index for the D47 variable
var_end_D47_monthly = var_start_D47_monthly + num_bins_monthly # Determine the end index for the D47 variable
var_start_d18Oc_monthly = var_names.index("d18O") * num_bins_monthly # Determine the start index for the d18Oc variable
var_end_d18Oc_monthly = var_start_d18Oc_monthly + num_bins_monthly # Determine the end index for the d18Oc variable

n_update_CESM_4PIC_D47 = n_update_CESM_4PIC[var_start_D47_monthly:var_end_D47_monthly]  # Extract the number of updates for D47
n_update_CESM_2PIC_D47 = n_update_CESM_2PIC[var_start_D47_monthly:var_end_D47_monthly]  # Extract the number of updates for D47
n_update_HadCM_new_1PIC_D47 = n_update_HadCM_new_1PIC[var_start_D47_monthly:var_end_D47_monthly]  # Extract the number of updates for D47
n_update_HadCM_new_2PIC_D47 = n_update_HadCM_new_2PIC[var_start_D47_monthly:var_end_D47_monthly]  # Extract the number of updates for D47
n_update_HadCM_new_1056ppm_D47 = n_update_HadCM_new_1056ppm[var_start_D47_monthly:var_end_D47_monthly]  # Extract the number of updates for D47
n_update_HadCM_old_2PIC_D47 = n_update_HadCM_old_2PIC[var_start_D47_monthly:var_end_D47_monthly]  # Extract the number of updates for D47
n_update_HadCM_old_4PIC_D47 = n_update_HadCM_old_4PIC[var_start_D47_monthly:var_end_D47_monthly]  # Extract the number of updates for D47

n_update_CESM_4PIC_d18Oc = n_update_CESM_4PIC[var_start_d18Oc_monthly:var_end_d18Oc_monthly]  # Extract the number of updates for d18Oc
n_update_CESM_2PIC_d18Oc = n_update_CESM_2PIC[var_start_d18Oc_monthly:var_end_d18Oc_monthly]  # Extract the number of updates for d18Oc
n_update_HadCM_new_1PIC_d18Oc = n_update_HadCM_new_1PIC[var_start_d18Oc_monthly:var_end_d18Oc_monthly]  # Extract the number of updates for d18Oc
n_update_HadCM_new_2PIC_d18Oc = n_update_HadCM_new_2PIC[var_start_d18Oc_monthly:var_end_d18Oc_monthly]  # Extract the number of updates for d18Oc
n_update_HadCM_new_1056ppm_d18Oc = n_update_HadCM_new_1056ppm[var_start_d18Oc_monthly:var_end_d18Oc_monthly]  # Extract the number of updates for d18Oc
n_update_HadCM_old_2PIC_d18Oc = n_update_HadCM_old_2PIC[var_start_d18Oc_monthly:var_end_d18Oc_monthly]  # Extract the number of updates for d18Oc
n_update_HadCM_old_4PIC_d18Oc = n_update_HadCM_old_4PIC[var_start_d18Oc_monthly:var_end_d18Oc_monthly]  # Extract the number of updates for d18Oc
C:\Users\nwi213\AppData\Local\Temp\ipykernel_4724\2373763780.py:4: RuntimeWarning: invalid value encountered in sqrt
  std_post_HadCM_new_2PIC_SST_D47 = np.sqrt(np.diag(cov_post_HadCM_new_2PIC_SST_D47))
C:\Users\nwi213\AppData\Local\Temp\ipykernel_4724\2373763780.py:6: RuntimeWarning: invalid value encountered in sqrt
  std_post_HadCM_old_2PIC_SST_D47 = np.sqrt(np.diag(cov_post_HadCM_old_2PIC_SST_D47))
C:\Users\nwi213\AppData\Local\Temp\ipykernel_4724\2373763780.py:7: RuntimeWarning: invalid value encountered in sqrt
  std_post_HadCM_old_4PIC_SST_D47 = np.sqrt(np.diag(cov_post_HadCM_old_4PIC_SST_D47))

Then plot all priors and posteriors for d18Oc and D47¶

In [73]:
# Initialize subplots for monthly results
fig, axs = plt.subplots(2, 7, figsize=(20, 8), sharex = "col", sharey="row")

# Plot monthly results for each model and variable

# --- CESM 4x preindustrial pCO2 scenario ---

# --- D47 ---

# PRIOR
axs[0, 0].plot(months_scale, mu_prior_CESM_4PIC_SST_D47_monthly_original, label='Prior Mean', color='b', marker='o')
axs[0, 0].fill_between(
    months_scale,
    mu_prior_CESM_4PIC_SST_D47_monthly_original - stats.t.ppf(1 - 0.025, n_models_CESM_4PIC_monthly) * std_prior_CESM_4PIC_SST_D47_monthly_original / np.sqrt(n_models_CESM_4PIC_monthly),
    mu_prior_CESM_4PIC_SST_D47_monthly_original + stats.t.ppf(1 - 0.025, n_models_CESM_4PIC_monthly) * std_prior_CESM_4PIC_SST_D47_monthly_original / np.sqrt(n_models_CESM_4PIC_monthly),
    color='b',
    alpha=0.2,
    label='95% Confidence Interval'
)

# LIKELIHOOD
# Determine the start and end indices for the selected variable to parse information from the likelihood statistics
axs[0, 0].plot(months_scale, mu_likelihood[var_start_D47_monthly:var_end_D47_monthly], label='Likelihood Mean', color='y', marker='o')
axs[0, 0].fill_between(
    months_scale,
    mu_likelihood[var_start_D47_monthly:var_end_D47_monthly] - stats.t.ppf(1 - 0.025, n_update_CESM_4PIC_D47) * std_likelihood[var_start_D47_monthly:var_end_D47_monthly] / np.sqrt(n_update_CESM_4PIC_D47),
    mu_likelihood[var_start_D47_monthly:var_end_D47_monthly] + stats.t.ppf(1 - 0.025, n_update_CESM_4PIC_D47) * std_likelihood[var_start_D47_monthly:var_end_D47_monthly] / np.sqrt(n_update_CESM_4PIC_D47),
    color='y',
    alpha=0.2,
    label='95% Confidence Interval'
)
for measurement in Lutetian_data_monthly_aggregated_dict:
    axs[0, 0].plot(measurement["month_score"] + 1, measurement["D47_mean"], color="y", marker="o", alpha=0.2)
    axs[0, 0].errorbar(measurement["month_score"] + 1, measurement["D47_mean"], yerr=measurement["D47_SD"], color="y", alpha=0.2, capsize=5)

# POSTERIOR
axs[0, 0].plot(months_scale, mu_post_CESM_4PIC_SST_D47, label='Posterior Mean', color='r', marker='o')
axs[0, 0].fill_between(
    months_scale,
    mu_post_CESM_4PIC_SST_D47 - stats.t.ppf(1 - 0.025, (n_update_CESM_4PIC_D47 + n_models_CESM_4PIC_monthly)) * std_post_CESM_4PIC_SST_D47 / np.sqrt(n_update_CESM_4PIC_D47 + n_models_CESM_4PIC_monthly),
    mu_post_CESM_4PIC_SST_D47 + stats.t.ppf(1 - 0.025, (n_update_CESM_4PIC_D47 + n_models_CESM_4PIC_monthly)) * std_post_CESM_4PIC_SST_D47 / np.sqrt(n_update_CESM_4PIC_D47 + n_models_CESM_4PIC_monthly),
    color='r',
    alpha=0.2,
    label='95% Confidence Interval (Posterior)'
)

# Formatting
axs[0, 0].set_xticks(months_scale, month_names)
axs[0, 0].set_title('CESM\n4x preindustrial pCO2')
axs[0, 0].set_xlabel('Month')
axs[0, 0].set_ylabel('SST D47 value')
axs[0, 0].set_ylim(0.55, 0.65)
# axs[0, 0].legend()
axs[0, 0].grid(True)

# ---d18Oc---

# PRIOR
axs[1, 0].plot(months_scale, mu_prior_CESM_4PIC_d18Oc_monthly_original, label='Prior Mean', color='b', marker='o')
axs[1, 0].fill_between(
    months_scale,
    mu_prior_CESM_4PIC_d18Oc_monthly_original - stats.t.ppf(1 - 0.025, n_models_CESM_4PIC_monthly) * std_prior_CESM_4PIC_d18Oc_monthly_original / np.sqrt(n_models_CESM_4PIC_monthly),
    mu_prior_CESM_4PIC_d18Oc_monthly_original + stats.t.ppf(1 - 0.025, n_models_CESM_4PIC_monthly) * std_prior_CESM_4PIC_d18Oc_monthly_original / np.sqrt(n_models_CESM_4PIC_monthly),
    color='b',
    alpha=0.2,
    label='95% Confidence Interval'
)

# LIKELIHOOD
# Determine the start and end indices for the selected variable
axs[1, 0].plot(months_scale, mu_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly], label='Likelihood Mean', color='y', marker='o')
axs[1, 0].fill_between(
    months_scale,
    mu_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] - stats.t.ppf(1 - 0.025, n_update_CESM_4PIC_d18Oc) * std_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] / np.sqrt(n_update_CESM_4PIC_d18Oc),
    mu_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] + stats.t.ppf(1 - 0.025, n_update_CESM_4PIC_d18Oc) * std_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] / np.sqrt(n_update_CESM_4PIC_d18Oc),
    color='y',
    alpha=0.2,
    label='95% Confidence Interval'
)
for measurement in Lutetian_data_monthly_aggregated_dict:
    axs[1, 0].plot(measurement["month_score"] + 1, measurement["d18O"], color="y", marker="o", alpha=0.2)
    axs[1, 0].errorbar(measurement["month_score"] + 1, measurement["d18O"], yerr=measurement["d18O_SD"], color="y", alpha=0.2, capsize=5)

# POSTERIOR
axs[1, 0].plot(months_scale, mu_post_CESM_4PIC_d18Oc, label='Posterior Mean', color='r', marker='o')
axs[1, 0].fill_between(
    months_scale,
    mu_post_CESM_4PIC_d18Oc - stats.t.ppf(1 - 0.025, (n_update_CESM_4PIC_d18Oc + n_models_CESM_4PIC_monthly)) * std_post_CESM_4PIC_d18Oc / np.sqrt(n_update_CESM_4PIC_d18Oc + n_models_CESM_4PIC_monthly),
    mu_post_CESM_4PIC_d18Oc + stats.t.ppf(1 - 0.025, (n_update_CESM_4PIC_d18Oc + n_models_CESM_4PIC_monthly)) * std_post_CESM_4PIC_d18Oc / np.sqrt(n_update_CESM_4PIC_d18Oc + n_models_CESM_4PIC_monthly),
    color='r',
    alpha=0.2,
    label='95% Confidence Interval (Posterior)'
)

# Formatting
axs[1, 0].set_xticks(months_scale, month_names, rotation=45, ha='right')
axs[1, 0].set_xlabel('Month')
axs[1, 0].set_ylabel('d18Oc value')
# axs[1, 0].legend()
axs[1, 0].grid(True)

# --- CESM 2x preindustrial pCO2 scenario ---

# --- D47 ---

# PRIOR
axs[0, 1].plot(months_scale, mu_prior_CESM_2PIC_SST_D47_monthly_original, label='Prior Mean', color='b', marker='o')
axs[0, 1].fill_between(
    months_scale,
    mu_prior_CESM_2PIC_SST_D47_monthly_original - stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_SST_D47_monthly_original / np.sqrt(n_models_CESM_2PIC_monthly),
    mu_prior_CESM_2PIC_SST_D47_monthly_original + stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_SST_D47_monthly_original / np.sqrt(n_models_CESM_2PIC_monthly),
    color='b',
    alpha=0.2,
    label='95% Confidence Interval'
)

# LIKELIHOOD
axs[0, 1].plot(months_scale, mu_likelihood[var_start_D47_monthly:var_end_D47_monthly], label='Likelihood Mean', color='y', marker='o')
axs[0, 1].fill_between(
    months_scale,
    mu_likelihood[var_start_D47_monthly:var_end_D47_monthly] - stats.t.ppf(1 - 0.025, n_update_CESM_2PIC_D47) * std_likelihood[var_start_D47_monthly:var_end_D47_monthly] / np.sqrt(n_update_CESM_2PIC_D47),
    mu_likelihood[var_start_D47_monthly:var_end_D47_monthly] + stats.t.ppf(1 - 0.025, n_update_CESM_2PIC_D47) * std_likelihood[var_start_D47_monthly:var_end_D47_monthly] / np.sqrt(n_update_CESM_2PIC_D47),
    color='y',
    alpha=0.2,
    label='95% Confidence Interval'
)

# POSTERIOR
axs[0, 1].plot(months_scale, mu_post_CESM_2PIC_SST_D47, label='Posterior Mean', color='r', marker='o')
axs[0, 1].fill_between(
    months_scale,
    mu_post_CESM_2PIC_SST_D47 - stats.t.ppf(1 - 0.025, (n_update_CESM_2PIC_D47 + n_models_CESM_2PIC_monthly)) * std_post_CESM_2PIC_SST_D47 / np.sqrt(n_update_CESM_2PIC_D47 + n_models_CESM_2PIC_monthly),
    mu_post_CESM_2PIC_SST_D47 + stats.t.ppf(1 - 0.025, (n_update_CESM_2PIC_D47 + n_models_CESM_2PIC_monthly)) * std_post_CESM_2PIC_SST_D47 / np.sqrt(n_update_CESM_2PIC_D47 + n_models_CESM_2PIC_monthly),
    color='r',
    alpha=0.2,
    label='95% Confidence Interval (Posterior)'
)

# Formatting
axs[0, 1].set_xticks(months_scale, month_names)
axs[0, 1].set_title('CESM\n2x preindustrial pCO2')
axs[0, 1].set_xlabel('Month')
axs[0, 1].set_ylabel('SST D47 value')
# axs[0, 1].legend()
axs[0, 1].grid(True)

# ---d18Oc---

# PRIOR
axs[1, 1].plot(months_scale, mu_prior_CESM_2PIC_d18Oc_monthly_original, label='Prior Mean', color='b', marker='o')
axs[1, 1].fill_between(
    months_scale,
    mu_prior_CESM_2PIC_d18Oc_monthly_original - stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_d18Oc_monthly_original / np.sqrt(n_models_CESM_2PIC_monthly),
    mu_prior_CESM_2PIC_d18Oc_monthly_original + stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_d18Oc_monthly_original / np.sqrt(n_models_CESM_2PIC_monthly),
    color='b',
    alpha=0.2,
    label='95% Confidence Interval'
)

# LIKELIHOOD
axs[1, 1].plot(months_scale, mu_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly], label='Likelihood Mean', color='y', marker='o')
axs[1, 1].fill_between(
    months_scale,
    mu_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] - stats.t.ppf(1 - 0.025, n_update_CESM_2PIC_d18Oc) * std_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] / np.sqrt(n_update_CESM_2PIC_d18Oc),
    mu_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] + stats.t.ppf(1 - 0.025, n_update_CESM_2PIC_d18Oc) * std_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] / np.sqrt(n_update_CESM_2PIC_d18Oc),
    color='y',
    alpha=0.2,
    label='95% Confidence Interval'
)

# POSTERIOR
axs[1, 1].plot(months_scale, mu_post_CESM_2PIC_d18Oc, label='Posterior Mean', color='r', marker='o')
axs[1, 1].fill_between(
    months_scale,
    mu_post_CESM_2PIC_d18Oc - stats.t.ppf(1 - 0.025, (n_update_CESM_2PIC_d18Oc + n_models_CESM_2PIC_monthly)) * std_post_CESM_2PIC_d18Oc / np.sqrt(n_update_CESM_2PIC_d18Oc + n_models_CESM_2PIC_monthly),
    mu_post_CESM_2PIC_d18Oc + stats.t.ppf(1 - 0.025, (n_update_CESM_2PIC_d18Oc + n_models_CESM_2PIC_monthly)) * std_post_CESM_2PIC_d18Oc / np.sqrt(n_update_CESM_2PIC_d18Oc + n_models_CESM_2PIC_monthly),
    color='r',
    alpha=0.2,
    label='95% Confidence Interval (Posterior)'
)

# Formatting
axs[1, 1].set_xticks(months_scale, month_names, rotation=45, ha='right')
axs[1, 1].set_xlabel('Month')
axs[1, 1].set_ylabel('d18Oc value')
# axs[1, 1].legend()
axs[1, 1].grid(True)

# --- HadCM (new) 1x preindustrial pCO2 scenario ---

# --- D47 ---

# PRIOR
axs[0, 2].plot(months_scale, mu_prior_HadCM_new_1PIC_SST_D47_monthly_original, label='Prior Mean', color='b', marker='o')
axs[0, 2].fill_between(
    months_scale,
    mu_prior_HadCM_new_1PIC_SST_D47_monthly_original - stats.t.ppf(1 - 0.025, n_models_HadCM_new_1PIC_monthly) * std_prior_HadCM_new_1PIC_SST_D47_monthly_original / np.sqrt(n_models_HadCM_new_1PIC_monthly),
    mu_prior_HadCM_new_1PIC_SST_D47_monthly_original + stats.t.ppf(1 - 0.025, n_models_HadCM_new_1PIC_monthly) * std_prior_HadCM_new_1PIC_SST_D47_monthly_original / np.sqrt(n_models_HadCM_new_1PIC_monthly),
    color='b',
    alpha=0.2,
    label='95% Confidence Interval'
)

# LIKELIHOOD
axs[0, 2].plot(months_scale, mu_likelihood[var_start_D47_monthly:var_end_D47_monthly], label='Likelihood Mean', color='y', marker='o')
axs[0, 2].fill_between(
    months_scale,
    mu_likelihood[var_start_D47_monthly:var_end_D47_monthly] - stats.t.ppf(1 - 0.025, n_update_HadCM_new_1PIC_D47) * std_likelihood[var_start_D47_monthly:var_end_D47_monthly] / np.sqrt(n_update_HadCM_new_1PIC_D47),
    mu_likelihood[var_start_D47_monthly:var_end_D47_monthly] + stats.t.ppf(1 - 0.025, n_update_HadCM_new_1PIC_D47) * std_likelihood[var_start_D47_monthly:var_end_D47_monthly] / np.sqrt(n_update_HadCM_new_1PIC_D47),
    color='y',
    alpha=0.2,
    label='95% Confidence Interval'
)

# POSTERIOR
axs[0, 2].plot(months_scale, mu_post_HadCM_new_1PIC_SST_D47, label='Posterior Mean', color='r', marker='o')
axs[0, 2].fill_between(
    months_scale,
    mu_post_HadCM_new_1PIC_SST_D47 - stats.t.ppf(1 - 0.025, (n_update_HadCM_new_1PIC_D47 + n_models_HadCM_new_1PIC_monthly)) * std_post_HadCM_new_1PIC_SST_D47 / np.sqrt(n_update_HadCM_new_1PIC_D47 + n_models_HadCM_new_1PIC_monthly),
    mu_post_HadCM_new_1PIC_SST_D47 + stats.t.ppf(1 - 0.025, (n_update_HadCM_new_1PIC_D47 + n_models_HadCM_new_1PIC_monthly)) * std_post_HadCM_new_1PIC_SST_D47 / np.sqrt(n_update_HadCM_new_1PIC_D47 + n_models_HadCM_new_1PIC_monthly),
    color='r',
    alpha=0.2,
    label='95% Confidence Interval (Posterior)'
)

# Formatting
axs[0, 2].set_xticks(months_scale, month_names)
axs[0, 2].set_title('HadCM\n1x preindustrial pCO2')
axs[0, 2].set_xlabel('Month')
axs[0, 2].set_ylabel('SST D47 value')
# axs[0, 2].legend()
axs[0, 2].grid(True)

# ---d18Oc---

# PRIOR
axs[1, 2].plot(months_scale, mu_prior_HadCM_new_1PIC_d18Oc_monthly_original, label='Prior Mean', color='b', marker='o')
axs[1, 2].fill_between(
    months_scale,
    mu_prior_HadCM_new_1PIC_d18Oc_monthly_original - stats.t.ppf(1 - 0.025, n_models_HadCM_new_1PIC_monthly) * std_prior_HadCM_new_1PIC_d18Oc_monthly_original / np.sqrt(n_models_HadCM_new_1PIC_monthly),
    mu_prior_HadCM_new_1PIC_d18Oc_monthly_original + stats.t.ppf(1 - 0.025, n_models_HadCM_new_1PIC_monthly) * std_prior_HadCM_new_1PIC_d18Oc_monthly_original / np.sqrt(n_models_HadCM_new_1PIC_monthly),
    color='b',
    alpha=0.2,
    label='95% Confidence Interval'
)

# LIKELIHOOD
axs[1, 2].plot(months_scale, mu_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly], label='Likelihood Mean', color='y', marker='o')
axs[1, 2].fill_between(
    months_scale,
    mu_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] - stats.t.ppf(1 - 0.025, n_update_HadCM_new_1PIC_d18Oc) * std_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] / np.sqrt(n_update_HadCM_new_1PIC_d18Oc),
    mu_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] + stats.t.ppf(1 - 0.025, n_update_HadCM_new_1PIC_d18Oc) * std_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] / np.sqrt(n_update_HadCM_new_1PIC_d18Oc),
    color='y',
    alpha=0.2,
    label='95% Confidence Interval'
)

# POSTERIOR
axs[1, 2].plot(months_scale, mu_post_HadCM_new_1PIC_d18Oc, label='Posterior Mean', color='r', marker='o')
axs[1, 2].fill_between(
    months_scale,
    mu_post_HadCM_new_1PIC_d18Oc - stats.t.ppf(1 - 0.025, (n_update_HadCM_new_1PIC_d18Oc + n_models_HadCM_new_1PIC_monthly)) * std_post_HadCM_new_1PIC_d18Oc / np.sqrt(n_update_HadCM_new_1PIC_d18Oc + n_models_HadCM_new_1PIC_monthly),
    mu_post_HadCM_new_1PIC_d18Oc + stats.t.ppf(1 - 0.025, (n_update_HadCM_new_1PIC_d18Oc + n_models_HadCM_new_1PIC_monthly)) * std_post_HadCM_new_1PIC_d18Oc / np.sqrt(n_update_HadCM_new_1PIC_d18Oc + n_models_HadCM_new_1PIC_monthly),
    color='r',
    alpha=0.2,
    label='95% Confidence Interval (Posterior)'
)

# Formatting
axs[1, 2].set_xticks(months_scale, month_names, rotation=45, ha='right')
axs[1, 2].set_xlabel('Month')
axs[1, 2].set_ylabel('d18Oc value')
# axs[1, 2].legend()
axs[1, 2].grid(True)


# --- HadCM (new) 2x preindustrial pCO2 scenario ---

# --- D47 ---

# PRIOR
axs[0, 3].plot(months_scale, mu_prior_HadCM_new_2PIC_SST_D47_monthly_original, label='Prior Mean', color='b', marker='o')
axs[0, 3].fill_between(
    months_scale,
    mu_prior_HadCM_new_2PIC_SST_D47_monthly_original - stats.t.ppf(1 - 0.025, n_models_HadCM_new_2PIC_monthly) * std_prior_HadCM_new_2PIC_SST_D47_monthly_original / np.sqrt(n_models_HadCM_new_2PIC_monthly),
    mu_prior_HadCM_new_2PIC_SST_D47_monthly_original + stats.t.ppf(1 - 0.025, n_models_HadCM_new_2PIC_monthly) * std_prior_HadCM_new_2PIC_SST_D47_monthly_original / np.sqrt(n_models_HadCM_new_2PIC_monthly),
    color='b',
    alpha=0.2,
    label='95% Confidence Interval'
)

# LIKELIHOOD
axs[0, 3].plot(months_scale, mu_likelihood[var_start_D47_monthly:var_end_D47_monthly], label='Likelihood Mean', color='y', marker='o')
axs[0, 3].fill_between(
    months_scale,
    mu_likelihood[var_start_D47_monthly:var_end_D47_monthly] - stats.t.ppf(1 - 0.025, n_update_HadCM_new_2PIC_D47) * std_likelihood[var_start_D47_monthly:var_end_D47_monthly] / np.sqrt(n_update_HadCM_new_2PIC_D47),
    mu_likelihood[var_start_D47_monthly:var_end_D47_monthly] + stats.t.ppf(1 - 0.025, n_update_HadCM_new_2PIC_D47) * std_likelihood[var_start_D47_monthly:var_end_D47_monthly] / np.sqrt(n_update_HadCM_new_2PIC_D47),
    color='y',
    alpha=0.2,
    label='95% Confidence Interval'
)

# POSTERIOR
axs[0, 3].plot(months_scale, mu_post_HadCM_new_2PIC_SST_D47, label='Posterior Mean', color='r', marker='o')
axs[0, 3].fill_between(
    months_scale,
    mu_post_HadCM_new_2PIC_SST_D47 - stats.t.ppf(1 - 0.025, (n_update_HadCM_new_2PIC_D47 + n_models_HadCM_new_2PIC_monthly)) * std_post_HadCM_new_2PIC_SST_D47 / np.sqrt(n_update_HadCM_new_2PIC_D47 + n_models_HadCM_new_2PIC_monthly),
    mu_post_HadCM_new_2PIC_SST_D47 + stats.t.ppf(1 - 0.025, (n_update_HadCM_new_2PIC_D47 + n_models_HadCM_new_2PIC_monthly)) * std_post_HadCM_new_2PIC_SST_D47 / np.sqrt(n_update_HadCM_new_2PIC_D47 + n_models_HadCM_new_2PIC_monthly),
    color='r',
    alpha=0.2,
    label='95% Confidence Interval (Posterior)'
)

# Formatting
axs[0, 3].set_xticks(months_scale, month_names)
axs[0, 3].set_title('HadCM\n2x preindustrial pCO2')
axs[0, 3].set_xlabel('Month')
axs[0, 3].set_ylabel('SST D47 value')
# axs[0, 3].legend()
axs[0, 3].grid(True)

# ---d18Oc---

# PRIOR
axs[1, 3].plot(months_scale, mu_prior_HadCM_new_2PIC_d18Oc_monthly_original, label='Prior Mean', color='b', marker='o')
axs[1, 3].fill_between(
    months_scale,
    mu_prior_HadCM_new_2PIC_d18Oc_monthly_original - stats.t.ppf(1 - 0.025, n_models_HadCM_new_2PIC_monthly) * std_prior_HadCM_new_2PIC_d18Oc_monthly_original / np.sqrt(n_models_HadCM_new_2PIC_monthly),
    mu_prior_HadCM_new_2PIC_d18Oc_monthly_original + stats.t.ppf(1 - 0.025, n_models_HadCM_new_2PIC_monthly) * std_prior_HadCM_new_2PIC_d18Oc_monthly_original / np.sqrt(n_models_HadCM_new_2PIC_monthly),
    color='b',
    alpha=0.2,
    label='95% Confidence Interval'
)

# LIKELIHOOD
axs[1, 3].plot(months_scale, mu_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly], label='Likelihood Mean', color='y', marker='o')
axs[1, 3].fill_between(
    months_scale,
    mu_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] - stats.t.ppf(1 - 0.025, n_update_HadCM_new_2PIC_d18Oc) * std_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] / np.sqrt(n_update_HadCM_new_2PIC_d18Oc),
    mu_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] + stats.t.ppf(1 - 0.025, n_update_HadCM_new_2PIC_d18Oc) * std_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] / np.sqrt(n_update_HadCM_new_2PIC_d18Oc),
    color='y',
    alpha=0.2,
    label='95% Confidence Interval'
)

# POSTERIOR
axs[1, 3].plot(months_scale, mu_post_HadCM_new_2PIC_d18Oc, label='Posterior Mean', color='r', marker='o')
axs[1, 3].fill_between(
    months_scale,
    mu_post_HadCM_new_2PIC_d18Oc - stats.t.ppf(1 - 0.025, (n_update_HadCM_new_2PIC_d18Oc + n_models_HadCM_new_2PIC_monthly)) * std_post_HadCM_new_2PIC_d18Oc / np.sqrt(n_update_HadCM_new_2PIC_d18Oc + n_models_HadCM_new_2PIC_monthly),
    mu_post_HadCM_new_2PIC_d18Oc + stats.t.ppf(1 - 0.025, (n_update_HadCM_new_2PIC_d18Oc + n_models_HadCM_new_2PIC_monthly)) * std_post_HadCM_new_2PIC_d18Oc / np.sqrt(n_update_HadCM_new_2PIC_d18Oc + n_models_HadCM_new_2PIC_monthly),
    color='r',
    alpha=0.2,
    label='95% Confidence Interval (Posterior)'
)

# Formatting
axs[1, 3].set_xticks(months_scale, month_names, rotation=45, ha='right')
axs[1, 3].set_xlabel('Month')
axs[1, 3].set_ylabel('d18Oc value')
# axs[1, 3].legend()
axs[1, 3].grid(True)


# --- HadCM (new) 1056 ppm pCO2 scenario ---

# --- D47 ---

# PRIOR
axs[0, 4].plot(months_scale, mu_prior_HadCM_new_1056ppm_SST_D47_monthly_original, label='Prior Mean', color='b', marker='o')
axs[0, 4].fill_between(
    months_scale,
    mu_prior_HadCM_new_1056ppm_SST_D47_monthly_original - stats.t.ppf(1 - 0.025, n_models_HadCM_new_1056ppm_monthly) * std_prior_HadCM_new_1056ppm_SST_D47_monthly_original / np.sqrt(n_models_HadCM_new_1056ppm_monthly),
    mu_prior_HadCM_new_1056ppm_SST_D47_monthly_original + stats.t.ppf(1 - 0.025, n_models_HadCM_new_1056ppm_monthly) * std_prior_HadCM_new_1056ppm_SST_D47_monthly_original / np.sqrt(n_models_HadCM_new_1056ppm_monthly),
    color='b',
    alpha=0.2,
    label='95% Confidence Interval'
)

# LIKELIHOOD
axs[0, 4].plot(months_scale, mu_likelihood[var_start_D47_monthly:var_end_D47_monthly], label='Likelihood Mean', color='y', marker='o')
axs[0, 4].fill_between(
    months_scale,
    mu_likelihood[var_start_D47_monthly:var_end_D47_monthly] - stats.t.ppf(1 - 0.025, n_update_HadCM_new_1056ppm_D47) * std_likelihood[var_start_D47_monthly:var_end_D47_monthly] / np.sqrt(n_update_HadCM_new_1056ppm_D47),
    mu_likelihood[var_start_D47_monthly:var_end_D47_monthly] + stats.t.ppf(1 - 0.025, n_update_HadCM_new_1056ppm_D47) * std_likelihood[var_start_D47_monthly:var_end_D47_monthly] / np.sqrt(n_update_HadCM_new_1056ppm_D47),
    color='y',
    alpha=0.2,
    label='95% Confidence Interval'
)

# POSTERIOR
axs[0, 4].plot(months_scale, mu_post_HadCM_new_1056ppm_SST_D47, label='Posterior Mean', color='r', marker='o')
axs[0, 4].fill_between(
    months_scale,
    mu_post_HadCM_new_1056ppm_SST_D47 - stats.t.ppf(1 - 0.025, (n_update_HadCM_new_1056ppm_D47 + n_models_HadCM_new_1056ppm_monthly)) * std_post_HadCM_new_1056ppm_SST_D47 / np.sqrt(n_update_HadCM_new_1056ppm_D47 + n_models_HadCM_new_1056ppm_monthly),
    mu_post_HadCM_new_1056ppm_SST_D47 + stats.t.ppf(1 - 0.025, (n_update_HadCM_new_1056ppm_D47 + n_models_HadCM_new_1056ppm_monthly)) * std_post_HadCM_new_1056ppm_SST_D47 / np.sqrt(n_update_HadCM_new_1056ppm_D47 + n_models_HadCM_new_1056ppm_monthly),
    color='r',
    alpha=0.2,
    label='95% Confidence Interval (Posterior)'
)

# Formatting
axs[0, 4].set_xticks(months_scale, month_names)
axs[0, 4].set_title('HadCM\n1056 ppm pCO2')
axs[0, 4].set_xlabel('Month')
axs[0, 4].set_ylabel('SST D47 value')
# axs[0, 4].legend()
axs[0, 4].grid(True)

# ---d18Oc---

# PRIOR
axs[1, 4].plot(months_scale, mu_prior_HadCM_new_1056ppm_d18Oc_monthly_original, label='Prior Mean', color='b', marker='o')
axs[1, 4].fill_between(
    months_scale,
    mu_prior_HadCM_new_1056ppm_d18Oc_monthly_original - stats.t.ppf(1 - 0.025, n_models_HadCM_new_1056ppm_monthly) * std_prior_HadCM_new_1056ppm_d18Oc_monthly_original / np.sqrt(n_models_HadCM_new_1056ppm_monthly),
    mu_prior_HadCM_new_1056ppm_d18Oc_monthly_original + stats.t.ppf(1 - 0.025, n_models_HadCM_new_1056ppm_monthly) * std_prior_HadCM_new_1056ppm_d18Oc_monthly_original / np.sqrt(n_models_HadCM_new_1056ppm_monthly),
    color='b',
    alpha=0.2,
    label='95% Confidence Interval'
)

# LIKELIHOOD
axs[1, 4].plot(months_scale, mu_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly], label='Likelihood Mean', color='y', marker='o')
axs[1, 4].fill_between(
    months_scale,
    mu_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] - stats.t.ppf(1 - 0.025, n_update_HadCM_new_1056ppm_d18Oc) * std_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] / np.sqrt(n_update_HadCM_new_1056ppm_d18Oc),
    mu_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] + stats.t.ppf(1 - 0.025, n_update_HadCM_new_1056ppm_d18Oc) * std_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] / np.sqrt(n_update_HadCM_new_1056ppm_d18Oc),
    color='y',
    alpha=0.2,
    label='95% Confidence Interval'
)

# POSTERIOR
axs[1, 4].plot(months_scale, mu_post_HadCM_new_1056ppm_d18Oc, label='Posterior Mean', color='r', marker='o')
axs[1, 4].fill_between(
    months_scale,
    mu_post_HadCM_new_1056ppm_d18Oc - stats.t.ppf(1 - 0.025, (n_update_HadCM_new_1056ppm_d18Oc + n_models_HadCM_new_1056ppm_monthly)) * std_post_HadCM_new_1056ppm_d18Oc / np.sqrt(n_update_HadCM_new_1056ppm_d18Oc + n_models_HadCM_new_1056ppm_monthly),
    mu_post_HadCM_new_1056ppm_d18Oc + stats.t.ppf(1 - 0.025, (n_update_HadCM_new_1056ppm_d18Oc + n_models_HadCM_new_1056ppm_monthly)) * std_post_HadCM_new_1056ppm_d18Oc / np.sqrt(n_update_HadCM_new_1056ppm_d18Oc + n_models_HadCM_new_1056ppm_monthly),
    color='r',
    alpha=0.2,
    label='95% Confidence Interval (Posterior)'
)

# Formatting
axs[1, 4].set_xticks(months_scale, month_names, rotation=45, ha='right')
axs[1, 4].set_xlabel('Month')
axs[1, 4].set_ylabel('d18Oc value')
# axs[1, 4].legend()
axs[1, 4].grid(True)


# --- HadCM (old) 2x preindustrial pCO2 scenario ---

# --- D47 ---

# PRIOR
axs[0, 5].plot(months_scale, mu_prior_HadCM_old_2PIC_SST_D47_monthly_original, label='Prior Mean', color='b', marker='o')
axs[0, 5].fill_between(
    months_scale,
    mu_prior_HadCM_old_2PIC_SST_D47_monthly_original - stats.t.ppf(1 - 0.025, n_models_HadCM_old_2PIC_monthly) * std_prior_HadCM_old_2PIC_SST_D47_monthly_original / np.sqrt(n_models_HadCM_old_2PIC_monthly),
    mu_prior_HadCM_old_2PIC_SST_D47_monthly_original + stats.t.ppf(1 - 0.025, n_models_HadCM_old_2PIC_monthly) * std_prior_HadCM_old_2PIC_SST_D47_monthly_original / np.sqrt(n_models_HadCM_old_2PIC_monthly),
    color='b',
    alpha=0.2,
    label='95% Confidence Interval'
)

# LIKELIHOOD
axs[0, 5].plot(months_scale, mu_likelihood[var_start_D47_monthly:var_end_D47_monthly], label='Likelihood Mean', color='y', marker='o')
axs[0, 5].fill_between(
    months_scale,
    mu_likelihood[var_start_D47_monthly:var_end_D47_monthly] - stats.t.ppf(1 - 0.025, n_update_HadCM_old_2PIC_D47) * std_likelihood[var_start_D47_monthly:var_end_D47_monthly] / np.sqrt(n_update_HadCM_old_2PIC_D47),
    mu_likelihood[var_start_D47_monthly:var_end_D47_monthly] + stats.t.ppf(1 - 0.025, n_update_HadCM_old_2PIC_D47) * std_likelihood[var_start_D47_monthly:var_end_D47_monthly] / np.sqrt(n_update_HadCM_old_2PIC_D47),
    color='y',
    alpha=0.2,
    label='95% Confidence Interval'
)

# POSTERIOR
axs[0, 5].plot(months_scale, mu_post_HadCM_old_2PIC_SST_D47, label='Posterior Mean', color='r', marker='o')
axs[0, 5].fill_between(
    months_scale,
    mu_post_HadCM_old_2PIC_SST_D47 - stats.t.ppf(1 - 0.025, (n_update_HadCM_old_2PIC_D47 + n_models_HadCM_old_2PIC_monthly)) * std_post_HadCM_old_2PIC_SST_D47 / np.sqrt(n_update_HadCM_old_2PIC_D47 + n_models_HadCM_old_2PIC_monthly),
    mu_post_HadCM_old_2PIC_SST_D47 + stats.t.ppf(1 - 0.025, (n_update_HadCM_old_2PIC_D47 + n_models_HadCM_old_2PIC_monthly)) * std_post_HadCM_old_2PIC_SST_D47 / np.sqrt(n_update_HadCM_old_2PIC_D47 + n_models_HadCM_old_2PIC_monthly),
    color='r',
    alpha=0.2,
    label='95% Confidence Interval (Posterior)'
)

# Formatting
axs[0, 5].set_xticks(months_scale, month_names)
axs[0, 5].set_title('HadCM (old)\n2x preindustrial pCO2')
axs[0, 5].set_xlabel('Month')
axs[0, 5].set_ylabel('SST D47 value')
# axs[0, 5].legend()
axs[0, 5].grid(True)

# ---d18Oc---

# PRIOR
axs[1, 5].plot(months_scale, mu_prior_HadCM_old_2PIC_d18Oc_monthly_original, label='Prior Mean', color='b', marker='o')
axs[1, 5].fill_between(
    months_scale,
    mu_prior_HadCM_old_2PIC_d18Oc_monthly_original - stats.t.ppf(1 - 0.025, n_models_HadCM_old_2PIC_monthly) * std_prior_HadCM_old_2PIC_d18Oc_monthly_original / np.sqrt(n_models_HadCM_old_2PIC_monthly),
    mu_prior_HadCM_old_2PIC_d18Oc_monthly_original + stats.t.ppf(1 - 0.025, n_models_HadCM_old_2PIC_monthly) * std_prior_HadCM_old_2PIC_d18Oc_monthly_original / np.sqrt(n_models_HadCM_old_2PIC_monthly),
    color='b',
    alpha=0.2,
    label='95% Confidence Interval'
)

# LIKELIHOOD
axs[1, 5].plot(months_scale, mu_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly], label='Likelihood Mean', color='y', marker='o')
axs[1, 5].fill_between(
    months_scale,
    mu_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] - stats.t.ppf(1 - 0.025, n_update_HadCM_old_2PIC_d18Oc) * std_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] / np.sqrt(n_update_HadCM_old_2PIC_d18Oc),
    mu_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] + stats.t.ppf(1 - 0.025, n_update_HadCM_old_2PIC_d18Oc) * std_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] / np.sqrt(n_update_HadCM_old_2PIC_d18Oc),
    color='y',
    alpha=0.2,
    label='95% Confidence Interval'
)

# POSTERIOR
axs[1, 5].plot(months_scale, mu_post_HadCM_old_2PIC_d18Oc, label='Posterior Mean', color='r', marker='o')
axs[1, 5].fill_between(
    months_scale,
    mu_post_HadCM_old_2PIC_d18Oc - stats.t.ppf(1 - 0.025, (n_update_HadCM_old_2PIC_d18Oc + n_models_HadCM_old_2PIC_monthly)) * std_post_HadCM_old_2PIC_d18Oc / np.sqrt(n_update_HadCM_old_2PIC_d18Oc + n_models_HadCM_old_2PIC_monthly),
    mu_post_HadCM_old_2PIC_d18Oc + stats.t.ppf(1 - 0.025, (n_update_HadCM_old_2PIC_d18Oc + n_models_HadCM_old_2PIC_monthly)) * std_post_HadCM_old_2PIC_d18Oc / np.sqrt(n_update_HadCM_old_2PIC_d18Oc + n_models_HadCM_old_2PIC_monthly),
    color='r',
    alpha=0.2,
    label='95% Confidence Interval (Posterior)'
)

# Formatting
axs[1, 5].set_xticks(months_scale, month_names, rotation=45, ha='right')
axs[1, 5].set_xlabel('Month')
axs[1, 5].set_ylabel('d18Oc value')
# axs[1, 5].legend()
axs[1, 5].grid(True)

# --- HadCM (old) 4x preindustrial pCO2 scenario ---

# --- D47 ---

# PRIOR
axs[0, 6].plot(months_scale, mu_prior_HadCM_old_4PIC_SST_D47_monthly_original, label='Prior Mean', color='b', marker='o')
axs[0, 6].fill_between(
    months_scale,
    mu_prior_HadCM_old_4PIC_SST_D47_monthly_original - stats.t.ppf(1 - 0.025, n_models_HadCM_old_4PIC_monthly) * std_prior_HadCM_old_4PIC_SST_D47_monthly_original / np.sqrt(n_models_HadCM_old_4PIC_monthly),
    mu_prior_HadCM_old_4PIC_SST_D47_monthly_original + stats.t.ppf(1 - 0.025, n_models_HadCM_old_4PIC_monthly) * std_prior_HadCM_old_4PIC_SST_D47_monthly_original / np.sqrt(n_models_HadCM_old_4PIC_monthly),
    color='b',
    alpha=0.2,
    label='95% Confidence Interval'
)

# LIKELIHOOD
axs[0, 6].plot(months_scale, mu_likelihood[var_start_D47_monthly:var_end_D47_monthly], label='Likelihood Mean', color='y', marker='o')
axs[0, 6].fill_between(
    months_scale,
    mu_likelihood[var_start_D47_monthly:var_end_D47_monthly] - stats.t.ppf(1 - 0.025, n_update_HadCM_old_4PIC_D47) * std_likelihood[var_start_D47_monthly:var_end_D47_monthly] / np.sqrt(n_update_HadCM_old_4PIC_D47),
    mu_likelihood[var_start_D47_monthly:var_end_D47_monthly] + stats.t.ppf(1 - 0.025, n_update_HadCM_old_4PIC_D47) * std_likelihood[var_start_D47_monthly:var_end_D47_monthly] / np.sqrt(n_update_HadCM_old_4PIC_D47),
    color='y',
    alpha=0.2,
    label='95% Confidence Interval'
)

# POSTERIOR
axs[0, 6].plot(months_scale, mu_post_HadCM_old_4PIC_SST_D47, label='Posterior Mean', color='r', marker='o')
axs[0, 6].fill_between(
    months_scale,
    mu_post_HadCM_old_4PIC_SST_D47 - stats.t.ppf(1 - 0.025, (n_update_HadCM_old_4PIC_D47 + n_models_HadCM_old_4PIC_monthly)) * std_post_HadCM_old_4PIC_SST_D47 / np.sqrt(n_update_HadCM_old_4PIC_D47 + n_models_HadCM_old_4PIC_monthly),
    mu_post_HadCM_old_4PIC_SST_D47 + stats.t.ppf(1 - 0.025, (n_update_HadCM_old_4PIC_D47 + n_models_HadCM_old_4PIC_monthly)) * std_post_HadCM_old_4PIC_SST_D47 / np.sqrt(n_update_HadCM_old_4PIC_D47 + n_models_HadCM_old_4PIC_monthly),
    color='r',
    alpha=0.2,
    label='95% Confidence Interval (Posterior)'
)

# Formatting
axs[0, 6].set_xticks(months_scale, month_names)
axs[0, 6].set_title('HadCM (old)\n4x preindustrial pCO2')
axs[0, 6].set_xlabel('Month')
axs[0, 6].set_ylabel('SST D47 value')
axs[0, 6].legend()
axs[0, 6].grid(True)

# ---d18Oc---

# PRIOR
axs[1, 6].plot(months_scale, mu_prior_HadCM_old_4PIC_d18Oc_monthly_original, label='Prior Mean', color='b', marker='o')
axs[1, 6].fill_between(
    months_scale,
    mu_prior_HadCM_old_4PIC_d18Oc_monthly_original - stats.t.ppf(1 - 0.025, n_models_HadCM_old_4PIC_monthly) * std_prior_HadCM_old_4PIC_d18Oc_monthly_original / np.sqrt(n_models_HadCM_old_4PIC_monthly),
    mu_prior_HadCM_old_4PIC_d18Oc_monthly_original + stats.t.ppf(1 - 0.025, n_models_HadCM_old_4PIC_monthly) * std_prior_HadCM_old_4PIC_d18Oc_monthly_original / np.sqrt(n_models_HadCM_old_4PIC_monthly),
    color='b',
    alpha=0.2,
    label='95% Confidence Interval'
)

# LIKELIHOOD
axs[1, 6].plot(months_scale, mu_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly], label='Likelihood Mean', color='y', marker='o')
axs[1, 6].fill_between(
    months_scale,
    mu_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] - stats.t.ppf(1 - 0.025, n_update_HadCM_old_4PIC_d18Oc) * std_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] / np.sqrt(n_update_HadCM_old_4PIC_d18Oc),
    mu_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] + stats.t.ppf(1 - 0.025, n_update_HadCM_old_4PIC_d18Oc) * std_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] / np.sqrt(n_update_HadCM_old_4PIC_d18Oc),
    color='y',
    alpha=0.2,
    label='95% Confidence Interval'
)

# POSTERIOR
axs[1, 6].plot(months_scale, mu_post_HadCM_old_4PIC_d18Oc, label='Posterior Mean', color='r', marker='o')
axs[1, 6].fill_between(
    months_scale,
    mu_post_HadCM_old_4PIC_d18Oc - stats.t.ppf(1 - 0.025, (n_update_HadCM_old_4PIC_d18Oc + n_models_HadCM_old_4PIC_monthly)) * std_post_HadCM_old_4PIC_d18Oc / np.sqrt(n_update_HadCM_old_4PIC_d18Oc + n_models_HadCM_old_4PIC_monthly),
    mu_post_HadCM_old_4PIC_d18Oc + stats.t.ppf(1 - 0.025, (n_update_HadCM_old_4PIC_d18Oc + n_models_HadCM_old_4PIC_monthly)) * std_post_HadCM_old_4PIC_d18Oc / np.sqrt(n_update_HadCM_old_4PIC_d18Oc + n_models_HadCM_old_4PIC_monthly),
    color='r',
    alpha=0.2,
    label='95% Confidence Interval (Posterior)'
)

# Formatting
axs[1, 6].set_xticks(months_scale, month_names, rotation=45, ha='right')
axs[1, 6].set_xlabel('Month')
axs[1, 6].set_ylabel('d18Oc value')
axs[1, 6].legend()
axs[1, 6].grid(True)

plt.suptitle('Monthly Prior and Posterior Means with 95% Confidence Intervals', fontsize = 16)
plt.show()
No description has been provided for this image

PLOT PRIOR AND LIKELIHOOD FOR MANUSCRIPT¶

In [74]:
# Set dimensions of data
n_models_monthly = len(Lutetian_CESM_2PIC_model["Cell"])  # Find the total number of models

# Create list of month names
months = ['ja', 'fb', 'mr', 'ar', 'my', 'jn', 'jl', 'ag', 'sp', 'ot', 'nv', 'dc']

# Create a monthly scale for the x-axis
month_names = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']  # List full month names
months_scale = np.arange(len(months)) + 1  # Create monthly scale

# Create the figure and axes
fig, axes = plt.subplots(7, 3, figsize=(18, 20), sharex=True)

# Start with DA based on CESM model outcomes with 4x preindustrial pCO2 forcing

# Panel 1: Plot the prior distribution for SST and SAT
axes[0, 0].plot(months_scale, mu_prior_CESM_2PIC_SAT_monthly, label='Prior SAT Mean', marker='o', color='r')
axes[0, 0].plot(months_scale, mu_prior_CESM_2PIC_SST_monthly, label='Prior SST Mean', marker='o', color='b')

# Add 95% confidence intervals for SAT
axes[0, 0].fill_between(
    months_scale,
    mu_prior_CESM_2PIC_SAT_monthly - stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_SAT_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
    mu_prior_CESM_2PIC_SAT_monthly + stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_SAT_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
    alpha=0.2, color='r', label='SAT 95% CI'
)

# Add 95% confidence intervals for SST
axes[0, 0].fill_between(
    months_scale,
    mu_prior_CESM_2PIC_SST_monthly - stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_SST_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
    mu_prior_CESM_2PIC_SST_monthly + stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_SST_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
    alpha=0.2, color='b', label='SST 95% CI'
)

# axes[0].set_title('Prior Mean and 95% Confidence Interval for Monthly SST & SAT Values')
axes[0, 0].set_ylabel('Temperature (°C)')
axes[0, 0].legend()
axes[0, 0].grid(True)

# Panel 2: Plot the prior distribution for SSS and precipitation
axes[0, 1].plot(months_scale, mu_prior_CESM_2PIC_SSS_monthly, label='Prior SSS Mean', marker='o', color='g')
ax2 = axes[0, 1].twinx()  # Create a secondary y-axis for precipitation
ax2.plot(months_scale, mu_prior_CESM_2PIC_precip_monthly, label='Prior Precipitation Mean', marker='o', color='purple')

# Add 95% confidence intervals for SSS
axes[0, 1].fill_between(
    months_scale,
    mu_prior_CESM_2PIC_SSS_monthly - stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_SSS_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
    mu_prior_CESM_2PIC_SSS_monthly + stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_SSS_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
    alpha=0.2, color='g', label='SSS 95% CI'
)

# Add 95% confidence intervals for precipitation
ax2.fill_between(
    months_scale,
    mu_prior_CESM_2PIC_precip_monthly - stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_precip_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
    mu_prior_CESM_2PIC_precip_monthly + stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_precip_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
    alpha=0.2, color='purple', label='Precipitation 95% CI'
)

axes[0, 1].set_ylabel('SSS (psu)', color='g')
ax2.set_ylabel('Precipitation (mm/day)', color='purple')
axes[0, 1].set_title('Priors and likelihoods for Lutetian case study')
axes[0, 1].legend(loc='upper left')
ax2.legend(loc='upper right')
axes[0, 1].grid(True)

# Panel 3: Plot the likelihood distribution for D47 and d18Oc measurements
# Plot individual (non-aggregated) measurements with uncertainties
ax3 = axes[0, 2].twinx()  # secondary y-axis for d18Oc

# Plot D47 likelihood
# Determine the start and end indices for the selected variable to parse information from the likelihood statistics
axes[0, 2].plot(months_scale, mu_likelihood[var_start_D47_monthly:var_end_D47_monthly], marker='o', label='D47 means', color='darkred')
axes[0, 2].fill_between(
    months_scale,
    mu_likelihood[var_start_D47_monthly:var_end_D47_monthly] - 1.96 * np.sqrt(std_likelihood[var_start_D47_monthly:var_end_D47_monthly]),
    mu_likelihood[var_start_D47_monthly:var_end_D47_monthly] + 1.96 * np.sqrt(std_likelihood[var_start_D47_monthly:var_end_D47_monthly]),
    color='darkred',
    alpha=0.2,
    label='D47 95% CI'
)
for measurement in Lutetian_data_dict:
    x_jitter = measurement["month_score"] + 1 + np.random.uniform(-0.2, 0.2)
    axes[0, 2].plot(x_jitter, measurement["D47_final"], color="darkred", marker="o", alpha=0.2)
    axes[0, 2].errorbar(x_jitter, measurement["D47_final"], yerr=measurement["D47_SD"], color="darkred", alpha=0.2)

# Plot d18Oc likelihood
# Determine the start and end indices for the selected variable
ax3.plot(months_scale, mu_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly], marker='o', label='d18Oc means', color='darkblue')
ax3.fill_between(
    months_scale,
    mu_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] - 1.96 * np.sqrt(std_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly]),
    mu_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] + 1.96 * np.sqrt(std_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly]),
    color='darkblue',
    alpha=0.2,
    label='d18Oc 95% CI'
)
for measurement in Lutetian_data_dict:
    x_jitter = measurement["month_score"] + 1 + np.random.uniform(-0.2, 0.2)
    ax3.plot(x_jitter, measurement["d18O"], color="darkblue", marker="o", alpha=0.2)
    ax3.errorbar(x_jitter, measurement["d18O"], yerr=measurement["d18O_SD"], color="darkblue", alpha=0.2)

axes[0, 2].set_ylabel('D47 (per mille I-CDES)', color='darkred')
ax3.set_ylabel('d18Oc (per mille VPDB)', color='darkblue')
axes[0, 2].legend(loc='upper left')
ax3.legend(loc='upper right')
axes[0, 2].grid(True)

# # Update the x-axis with month names
axes[0, 0].set_xticks(months_scale)
axes[0, 0].set_xticklabels(month_names, rotation=45, ha="right")
axes[0, 1].set_xticklabels(month_names, rotation=45, ha="right")
axes[0, 2].set_xticklabels(month_names, rotation=45, ha="right")

# Fill lower row of plot with DA outcomes based on CESM model with 2x preindustrial pCO2 forcing

# Panel 1: Plot the prior distribution for SST and SAT
axes[1, 0].plot(months_scale, mu_prior_CESM_2PIC_SAT_monthly, label='Prior SAT Mean', marker='o', color='r')
axes[1, 0].plot(months_scale, mu_prior_CESM_2PIC_SST_monthly, label='Prior SST Mean', marker='o', color='b')

# Add 95% confidence intervals for SAT
axes[1, 0].fill_between(
    months_scale,
    mu_prior_CESM_2PIC_SAT_monthly - stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_SAT_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
    mu_prior_CESM_2PIC_SAT_monthly + stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_SAT_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
    alpha=0.2, color='r', label='SAT 95% CI'
)

# Add 95% confidence intervals for SST
axes[1, 0].fill_between(
    months_scale,
    mu_prior_CESM_2PIC_SST_monthly - stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_SST_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
    mu_prior_CESM_2PIC_SST_monthly + stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_SST_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
    alpha=0.2, color='b', label='SST 95% CI'
)

# axes[0].set_title('Prior Mean and 95% Confidence Interval for Monthly SST & SAT Values')
axes[1, 0].set_ylabel('Temperature (°C)')
axes[1, 0].legend()
axes[1, 0].grid(True)

# Panel 2: Plot the prior distribution for SSS and precipitation
axes[1, 1].plot(months_scale, mu_prior_CESM_2PIC_SSS_monthly, label='Prior SSS Mean', marker='o', color='g')
ax4 = axes[1, 1].twinx()  # Create a secondary y-axis for precipitation
ax4.plot(months_scale, mu_prior_CESM_2PIC_precip_monthly, label='Prior Precipitation Mean', marker='o', color='purple')

# Add 95% confidence intervals for SSS
axes[1, 1].fill_between(
    months_scale,
    mu_prior_CESM_2PIC_SSS_monthly - stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_SSS_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
    mu_prior_CESM_2PIC_SSS_monthly + stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_SSS_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
    alpha=0.2, color='g', label='SSS 95% CI'
)

# Add 95% confidence intervals for precipitation
ax4.fill_between(
    months_scale,
    mu_prior_CESM_2PIC_precip_monthly - stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_precip_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
    mu_prior_CESM_2PIC_precip_monthly + stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_precip_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
    alpha=0.2, color='purple', label='Precipitation 95% CI'
)

axes[1, 1].set_ylabel('SSS (psu)', color='g')
ax4.set_ylabel('Precipitation (mm/day)', color='purple')
axes[1, 1].set_title('Priors and likelihoods for Lutetian case study')
axes[1, 1].legend(loc='upper left')
ax4.legend(loc='upper right')
axes[1, 1].grid(True)

# Panel 3: Plot the likelihood distribution for D47 and d18Oc measurements
# Plot individual (non-aggregated) measurements with uncertainties
ax5 = axes[1, 2].twinx()  # secondary y-axis for d18Oc

# Plot D47 likelihood
# Determine the start and end indices for the selected variable to parse information from the likelihood statistics
axes[1, 2].plot(months_scale, mu_likelihood[var_start_D47_monthly:var_end_D47_monthly], marker='o', label='D47 means', color='darkred')
axes[1, 2].fill_between(
    months_scale,
    mu_likelihood[var_start_D47_monthly:var_end_D47_monthly] - 1.96 * np.sqrt(std_likelihood[var_start_D47_monthly:var_end_D47_monthly]),
    mu_likelihood[var_start_D47_monthly:var_end_D47_monthly] + 1.96 * np.sqrt(std_likelihood[var_start_D47_monthly:var_end_D47_monthly]),
    color='darkred',
    alpha=0.2,
    label='D47 95% CI'
)
for measurement in Lutetian_data_dict:
    x_jitter = measurement["month_score"] + 1 + np.random.uniform(-0.2, 0.2)
    axes[1, 2].plot(x_jitter, measurement["D47_final"], color="darkred", marker="o", alpha=0.2)
    axes[1, 2].errorbar(x_jitter, measurement["D47_final"], yerr=measurement["D47_SD"], color="darkred", alpha=0.2)

# Plot d18Oc likelihood
# Determine the start and end indices for the selected variable
ax5.plot(months_scale, mu_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly], marker='o', label='d18Oc means', color='darkblue')
ax5.fill_between(
    months_scale,
    mu_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] - 1.96 * np.sqrt(std_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly]),
    mu_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] + 1.96 * np.sqrt(std_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly]),
    color='darkblue',
    alpha=0.2,
    label='d18Oc 95% CI'
)
for measurement in Lutetian_data_dict:
    x_jitter = measurement["month_score"] + 1 + np.random.uniform(-0.2, 0.2)
    ax3.plot(x_jitter, measurement["d18O"], color="darkblue", marker="o", alpha=0.2)
    ax3.errorbar(x_jitter, measurement["d18O"], yerr=measurement["d18O_SD"], color="darkblue", alpha=0.2)

axes[1, 2].set_ylabel('D47 (per mille I-CDES)', color='darkred')
ax5.set_ylabel('d18Oc (per mille VPDB)', color='darkblue')
axes[1, 2].legend(loc='upper left')
ax5.legend(loc='upper right')
axes[1, 2].grid(True)

# # Update the x-axis with month names
axes[1, 0].set_xticks(months_scale)
axes[1, 0].set_xticklabels(month_names, rotation=45, ha="right")
axes[1, 1].set_xticklabels(month_names, rotation=45, ha="right")
axes[1, 2].set_xticklabels(month_names, rotation=45, ha="right")

# Set tight layout
fig.suptitle('Lutetian Case Study: Monthly Prior and Likelihood Means with 95% Confidence Intervals (CESM 2x preindustrial pCO2)', fontsize = 16)
plt.tight_layout()
No description has been provided for this image

POSTERIOR - MONTHLY¶

Monthly posterior in temperature and salinity domains with aggregated data¶

  • Data and model outcomes assembled per month
  • Ignore sclero-dating uncertainty
  • D47 data aggregated in monthly bins prior to assembly

Convert monthly prior, likelihood and posterior to temperature and salinity and plot¶

To calculate the covariance matrices for d18Ow based on covariance between d18Oc values for the equations of Grossman and Ku and Lecuyer et al. the following approach is followed:

  • Original formula: T = B - A * (d18Oc - d18Ow) (+ 0.27 for Grossman and Ku, but this term is irrelavant for covariance; A and B different per calibration equation)

First solve for d18Ow:

  • d18Ow (in VSMOW) = d18Oc - (B - T) / A (+ 0.27)
  • Partial derivative 1: d(d18Ow)/d(d18Oc) = 1
  • Partial derivative 2: d(d18Ow)/d(T) = 1 / A
  • cov(d18Ow) = d(d18Ow)/d(d18Oc) ^ 2 * cov(d18Oc) + d(d18Ow)/d(d18Oc) * d(d18Ow)/d(T) * crosscov(d18Oc, T) * transpose(crosscov(d18Oc, T)) + d(d18Ow)/d(T) ^ 2 * cov(T)

Define function for propagating uncertainty through d18Oc-d18Ow-temperature relationship¶

In [75]:
# Function to propagate covariance on d18Ow in case of linear d18Oc-d18Ow-T equation
def propagate_cov_d18Ow_linear(cov_c, cov_T, cov_cT, A):
    """
    Propagate covariance for:
        w = c - (B - T)/A (+ 0.27)
    where A and B are scalars and the term 0.27 is used to convert between SMOW and VSMOW, but only A is relevant for covariance

    Inputs:
        cov_c  : (n,n) covariance matrix of d18Oc
        cov_T  : (n,n) covariance matrix of T
        cov_cT : (n,n) cross-covariance matrix Cov(c,T)
        A      : scalar (slope)

    Returns:
        cov_w : (n,n) covariance matrix of d18Ow
    """

    dwdc = 1.0
    dwdT = 1.0 / A

    cov_w = (
        dwdc**2 * cov_c
        + dwdc * dwdT * (cov_cT + cov_cT.T)
        + dwdT**2 * cov_T
    )

    return cov_w

Execute SST and SSS error propagation for all model scenarios¶

In [76]:
# Convert prior D47 to temp
mu_prior_CESM_4PIC_SST_D47_monthly_T = D47c.OGLS23.T47(D47 = mu_prior_CESM_4PIC_SST_D47_monthly_original, sD47 = cov_prior_CESM_4PIC_SST_D47_monthly_original, return_covar = True)[0]
mu_prior_CESM_2PIC_SST_D47_monthly_T = D47c.OGLS23.T47(D47 = mu_prior_CESM_2PIC_SST_D47_monthly_original, sD47 = cov_prior_CESM_2PIC_SST_D47_monthly_original, return_covar = True)[0]
mu_prior_HadCM_new_1PIC_SST_D47_monthly_T = D47c.OGLS23.T47(D47 = mu_prior_HadCM_new_1PIC_SST_D47_monthly_original, sD47 = cov_prior_HadCM_new_1PIC_SST_D47_monthly_original, return_covar = True)[0]
mu_prior_HadCM_new_2PIC_SST_D47_monthly_T = D47c.OGLS23.T47(D47 = mu_prior_HadCM_new_2PIC_SST_D47_monthly_original, sD47 = cov_prior_HadCM_new_2PIC_SST_D47_monthly_original, return_covar = True)[0]
mu_prior_HadCM_new_1056ppm_SST_D47_monthly_T = D47c.OGLS23.T47(D47 = mu_prior_HadCM_new_1056ppm_SST_D47_monthly_original, sD47 = cov_prior_HadCM_new_1056ppm_SST_D47_monthly_original, return_covar = True)[0]
mu_prior_HadCM_old_2PIC_SST_D47_monthly_T = D47c.OGLS23.T47(D47 = mu_prior_HadCM_old_2PIC_SST_D47_monthly_original, sD47 = cov_prior_HadCM_old_2PIC_SST_D47_monthly_original, return_covar = True)[0]
mu_prior_HadCM_old_4PIC_SST_D47_monthly_T = D47c.OGLS23.T47(D47 = mu_prior_HadCM_old_4PIC_SST_D47_monthly_original, sD47 = cov_prior_HadCM_old_4PIC_SST_D47_monthly_original, return_covar = True)[0]

cov_prior_CESM_4PIC_SST_D47_monthly_T = D47c.OGLS23.T47(D47 = mu_prior_CESM_4PIC_SST_D47_monthly_original, sD47 = cov_prior_CESM_4PIC_SST_D47_monthly_original, return_covar = True)[1]
cov_prior_CESM_2PIC_SST_D47_monthly_T = D47c.OGLS23.T47(D47 = mu_prior_CESM_2PIC_SST_D47_monthly_original, sD47 = cov_prior_CESM_2PIC_SST_D47_monthly_original, return_covar = True)[1]
cov_prior_HadCM_new_1PIC_SST_D47_monthly_T = D47c.OGLS23.T47(D47 = mu_prior_HadCM_new_1PIC_SST_D47_monthly_original, sD47 = cov_prior_HadCM_new_1PIC_SST_D47_monthly_original, return_covar = True)[1]
cov_prior_HadCM_new_2PIC_SST_D47_monthly_T = D47c.OGLS23.T47(D47 = mu_prior_HadCM_new_2PIC_SST_D47_monthly_original, sD47 = cov_prior_HadCM_new_2PIC_SST_D47_monthly_original, return_covar = True)[1]
cov_prior_HadCM_new_1056ppm_SST_D47_monthly_T = D47c.OGLS23.T47(D47 = mu_prior_HadCM_new_1056ppm_SST_D47_monthly_original, sD47 = cov_prior_HadCM_new_1056ppm_SST_D47_monthly_original, return_covar = True)[1]
cov_prior_HadCM_old_2PIC_SST_D47_monthly_T = D47c.OGLS23.T47(D47 = mu_prior_HadCM_old_2PIC_SST_D47_monthly_original, sD47 = cov_prior_HadCM_old_2PIC_SST_D47_monthly_original, return_covar = True)[1]
cov_prior_HadCM_old_4PIC_SST_D47_monthly_T = D47c.OGLS23.T47(D47 = mu_prior_HadCM_old_4PIC_SST_D47_monthly_original, sD47 = cov_prior_HadCM_old_4PIC_SST_D47_monthly_original, return_covar = True)[1]

# Convert prior d18Oc and temperature to d18Ow
mu_prior_CESM_4PIC_d18Ow_monthly_T = mu_prior_CESM_4PIC_d18Oc_monthly_original - (20.6 - mu_prior_CESM_4PIC_SST_D47_monthly_T) / 4.34 + 0.27
mu_prior_CESM_2PIC_d18Ow_monthly_T = mu_prior_CESM_2PIC_d18Oc_monthly_original - (20.6 - mu_prior_CESM_2PIC_SST_D47_monthly_T) / 4.34 + 0.27
mu_prior_HadCM_new_1PIC_d18Ow_monthly_T = mu_prior_HadCM_new_1PIC_d18Oc_monthly_original - (20.6 - mu_prior_HadCM_new_1PIC_SST_D47_monthly_T) / 4.34 + 0.27
mu_prior_HadCM_new_2PIC_d18Ow_monthly_T = mu_prior_HadCM_new_2PIC_d18Oc_monthly_original - (20.6 - mu_prior_HadCM_new_2PIC_SST_D47_monthly_T) / 4.34 + 0.27
mu_prior_HadCM_new_1056ppm_d18Ow_monthly_T = mu_prior_HadCM_new_1056ppm_d18Oc_monthly_original - (20.6 - mu_prior_HadCM_new_1056ppm_SST_D47_monthly_T) / 4.34 + 0.27
mu_prior_HadCM_old_2PIC_d18Ow_monthly_T = mu_prior_HadCM_old_2PIC_d18Oc_monthly_original - (20.6 - mu_prior_HadCM_old_2PIC_SST_D47_monthly_T) / 4.34 + 0.27
mu_prior_HadCM_old_4PIC_d18Ow_monthly_T = mu_prior_HadCM_old_4PIC_d18Oc_monthly_original - (20.6 - mu_prior_HadCM_old_4PIC_SST_D47_monthly_T) / 4.34 + 0.27

# Calculate d18Oc-SST cross-covariance matrix
cross_cov_prior_CESM_4PIC_d18Oc_SST_monthly = np.cov(Lutetian_CESM_4PIC_model[SST_D47_CESM_4PIC_columns_monthly + d18Oc_CESM_4PIC_columns_monthly].dropna(), rowvar=False)[len(SST_D47_CESM_4PIC_columns_monthly):, :len(SST_D47_CESM_4PIC_columns_monthly)]
cross_cov_prior_CESM_2PIC_d18Oc_SST_monthly = np.cov(Lutetian_CESM_2PIC_model[SST_D47_CESM_2PIC_columns_monthly + d18Oc_CESM_2PIC_columns_monthly].dropna(), rowvar=False)[len(SST_D47_CESM_2PIC_columns_monthly):, :len(SST_D47_CESM_2PIC_columns_monthly)]
cross_cov_prior_HadCM_new_1PIC_d18Oc_SST_monthly = np.cov(Lutetian_HadCM_new_1PIC_model[SST_D47_HadCM_new_1PIC_columns_monthly + d18Oc_HadCM_new_1PIC_columns_monthly].dropna(), rowvar=False)[len(SST_D47_HadCM_new_1PIC_columns_monthly):, :len(SST_D47_HadCM_new_1PIC_columns_monthly)]
cross_cov_prior_HadCM_new_2PIC_d18Oc_SST_monthly = np.cov(Lutetian_HadCM_new_2PIC_model[SST_D47_HadCM_new_2PIC_columns_monthly + d18Oc_HadCM_new_2PIC_columns_monthly].dropna(), rowvar=False)[len(SST_D47_HadCM_new_2PIC_columns_monthly):, :len(SST_D47_HadCM_new_2PIC_columns_monthly)]
cross_cov_prior_HadCM_new_1056ppm_d18Oc_SST_monthly = np.cov(Lutetian_HadCM_new_1056ppm_model[SST_D47_HadCM_new_1056ppm_columns_monthly + d18Oc_HadCM_new_1056ppm_columns_monthly].dropna(), rowvar=False)[len(SST_D47_HadCM_new_1056ppm_columns_monthly):, :len(SST_D47_HadCM_new_1056ppm_columns_monthly)]
cross_cov_prior_HadCM_old_2PIC_d18Oc_SST_monthly = np.cov(Lutetian_HadCM_old_2PIC_model[SST_D47_HadCM_old_2PIC_columns_monthly + d18Oc_HadCM_old_2PIC_columns_monthly].dropna(), rowvar=False)[len(SST_D47_HadCM_old_2PIC_columns_monthly):, :len(SST_D47_HadCM_old_2PIC_columns_monthly)]
cross_cov_prior_HadCM_old_4PIC_d18Oc_SST_monthly = np.cov(Lutetian_HadCM_old_4PIC_model[SST_D47_HadCM_old_4PIC_columns_monthly + d18Oc_HadCM_old_4PIC_columns_monthly].dropna(), rowvar=False)[len(SST_D47_HadCM_old_4PIC_columns_monthly):, :len(SST_D47_HadCM_old_4PIC_columns_monthly)]

# Propagate covariance
cov_prior_CESM_4PIC_d18Ow_monthly_T = propagate_cov_d18Ow_linear(cov_prior_CESM_4PIC_d18Oc_monthly_original, cov_prior_CESM_4PIC_SST_D47_monthly_T, cross_cov_prior_CESM_4PIC_d18Oc_SST_monthly, 4.34)
cov_prior_CESM_2PIC_d18Ow_monthly_T = propagate_cov_d18Ow_linear(cov_prior_CESM_2PIC_d18Oc_monthly_original, cov_prior_CESM_2PIC_SST_D47_monthly_T, cross_cov_prior_CESM_2PIC_d18Oc_SST_monthly, 4.34)
cov_prior_HadCM_new_1PIC_d18Ow_monthly_T = propagate_cov_d18Ow_linear(cov_prior_HadCM_new_1PIC_d18Oc_monthly_original, cov_prior_HadCM_new_1PIC_SST_D47_monthly_T, cross_cov_prior_HadCM_new_1PIC_d18Oc_SST_monthly, 4.34)
cov_prior_HadCM_new_2PIC_d18Ow_monthly_T = propagate_cov_d18Ow_linear(cov_prior_HadCM_new_2PIC_d18Oc_monthly_original, cov_prior_HadCM_new_2PIC_SST_D47_monthly_T, cross_cov_prior_HadCM_new_2PIC_d18Oc_SST_monthly, 4.34)
cov_prior_HadCM_new_1056ppm_d18Ow_monthly_T = propagate_cov_d18Ow_linear(cov_prior_HadCM_new_1056ppm_d18Oc_monthly_original, cov_prior_HadCM_new_1056ppm_SST_D47_monthly_T, cross_cov_prior_HadCM_new_1056ppm_d18Oc_SST_monthly, 4.34)
cov_prior_HadCM_old_2PIC_d18Ow_monthly_T = propagate_cov_d18Ow_linear(cov_prior_HadCM_old_2PIC_d18Oc_monthly_original, cov_prior_HadCM_old_2PIC_SST_D47_monthly_T, cross_cov_prior_HadCM_old_2PIC_d18Oc_SST_monthly, 4.34)
cov_prior_HadCM_old_4PIC_d18Ow_monthly_T = propagate_cov_d18Ow_linear(cov_prior_HadCM_old_4PIC_d18Oc_monthly_original, cov_prior_HadCM_old_4PIC_SST_D47_monthly_T, cross_cov_prior_HadCM_old_4PIC_d18Oc_SST_monthly, 4.34)

# Convert prior d18Ow to SSS
mu_prior_CESM_4PIC_SSS_d18Ow_monthly_T = (mu_prior_CESM_4PIC_d18Ow_monthly_T + 9.300) / 0.274
mu_prior_CESM_2PIC_SSS_d18Ow_monthly_T = (mu_prior_CESM_2PIC_d18Ow_monthly_T + 9.300) / 0.274
mu_prior_HadCM_new_1PIC_SSS_d18Ow_monthly_T = (mu_prior_HadCM_new_1PIC_d18Ow_monthly_T + 9.300) / 0.274
mu_prior_HadCM_new_2PIC_SSS_d18Ow_monthly_T = (mu_prior_HadCM_new_2PIC_d18Ow_monthly_T + 9.300) / 0.274
mu_prior_HadCM_new_1056ppm_SSS_d18Ow_monthly_T = (mu_prior_HadCM_new_1056ppm_d18Ow_monthly_T + 9.300) / 0.274
mu_prior_HadCM_old_2PIC_SSS_d18Ow_monthly_T = (mu_prior_HadCM_old_2PIC_d18Ow_monthly_T + 9.300) / 0.274
mu_prior_HadCM_old_4PIC_SSS_d18Ow_monthly_T = (mu_prior_HadCM_old_4PIC_d18Ow_monthly_T + 9.300) / 0.274

cov_prior_CESM_4PIC_SSS_d18Ow_monthly_T = cov_prior_CESM_4PIC_d18Ow_monthly_T / (0.274 ** 2)
cov_prior_CESM_2PIC_SSS_d18Ow_monthly_T = cov_prior_CESM_2PIC_d18Ow_monthly_T / (0.274 ** 2)
cov_prior_HadCM_new_1PIC_SSS_d18Ow_monthly_T = cov_prior_HadCM_new_1PIC_d18Ow_monthly_T / (0.274 ** 2)
cov_prior_HadCM_new_2PIC_SSS_d18Ow_monthly_T = cov_prior_HadCM_new_2PIC_d18Ow_monthly_T / (0.274 ** 2)
cov_prior_HadCM_new_1056ppm_SSS_d18Ow_monthly_T = cov_prior_HadCM_new_1056ppm_d18Ow_monthly_T / (0.274 ** 2)
cov_prior_HadCM_old_2PIC_SSS_d18Ow_monthly_T = cov_prior_HadCM_old_2PIC_d18Ow_monthly_T / (0.274 ** 2)
cov_prior_HadCM_old_4PIC_SSS_d18Ow_monthly_T = cov_prior_HadCM_old_4PIC_d18Ow_monthly_T / (0.274 ** 2)

# Convert likelihood D47 to temp
# FIXME: likelihood vectors contain NAs, need to handle that properly
mu_likelihood_T = D47c.OGLS23.T47(D47 = mu_likelihood[var_start_D47_monthly:var_end_D47_monthly], sD47 = std_likelihood[var_start_D47_monthly:var_end_D47_monthly], return_covar = True)[0]
cov_likelihood_T = D47c.OGLS23.T47(D47 = mu_likelihood[var_start_D47_monthly:var_end_D47_monthly], sD47 = std_likelihood[var_start_D47_monthly:var_end_D47_monthly], return_covar = True)[1]

# Convert likelihood d18Oc and temperature to d18Ow (curently not implemented in data tracking function)
mu_likelihood_d18Ow_T = mu_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] - (20.6 - mu_likelihood_T) / 4.34 + 0.27
std_likelihood_d18Ow_T = np.sqrt(
    np.diag(
        propagate_cov_d18Ow_linear(
            np.diag(std_likelihood[var_start_d18Oc_monthly:var_end_d18Oc_monthly] ** 2),
            cov_likelihood_T,
            cross_cov_prior_CESM_4PIC_d18Oc_SST_monthly,
            4.34
        )
    )
)

# Convert likelihood d18Ow to SSS (currently not implemented in data tracking function)
mu_likelihood_SSS_d18Ow_T = (mu_likelihood_d18Ow_T + 9.300) / 0.274
std_likelihood_SSS_d18Ow_T = std_likelihood_d18Ow_T / (0.274 ** 2)

# Convert posterior D47 to temp
mu_post_CESM_4PIC_SST_D47_T = D47c.OGLS23.T47(D47 = mu_post_CESM_4PIC_SST_D47, sD47 = cov_post_CESM_4PIC_SST_D47, return_covar = True)[0]
mu_post_CESM_2PIC_SST_D47_T = D47c.OGLS23.T47(D47 = mu_post_CESM_2PIC_SST_D47, sD47 = cov_post_CESM_2PIC_SST_D47, return_covar = True)[0]
mu_post_HadCM_new_1PIC_SST_D47_T = D47c.OGLS23.T47(D47 = mu_post_HadCM_new_1PIC_SST_D47, sD47 = cov_post_HadCM_new_1PIC_SST_D47, return_covar = True)[0]
mu_post_HadCM_new_2PIC_SST_D47_T = D47c.OGLS23.T47(D47 = mu_post_HadCM_new_2PIC_SST_D47, sD47 = cov_post_HadCM_new_2PIC_SST_D47, return_covar = True)[0]
mu_post_HadCM_new_1056ppm_SST_D47_T = D47c.OGLS23.T47(D47 = mu_post_HadCM_new_1056ppm_SST_D47, sD47 = cov_post_HadCM_new_1056ppm_SST_D47, return_covar = True)[0]
mu_post_HadCM_old_2PIC_SST_D47_T = D47c.OGLS23.T47(D47 = mu_post_HadCM_old_2PIC_SST_D47, sD47 = cov_post_HadCM_old_2PIC_SST_D47, return_covar = True)[0]
mu_post_HadCM_old_4PIC_SST_D47_T = D47c.OGLS23.T47(D47 = mu_post_HadCM_old_4PIC_SST_D47, sD47 = cov_post_HadCM_old_4PIC_SST_D47, return_covar = True)[0]

cov_post_CESM_4PIC_SST_D47_T = D47c.OGLS23.T47(D47 = mu_post_CESM_4PIC_SST_D47, sD47 = cov_post_CESM_4PIC_SST_D47, return_covar = True)[1]
cov_post_CESM_2PIC_SST_D47_T = D47c.OGLS23.T47(D47 = mu_post_CESM_2PIC_SST_D47, sD47 = cov_post_CESM_2PIC_SST_D47, return_covar = True)[1]
cov_post_HadCM_new_1PIC_SST_D47_T = D47c.OGLS23.T47(D47 = mu_post_HadCM_new_1PIC_SST_D47, sD47 = cov_post_HadCM_new_1PIC_SST_D47, return_covar = True)[1]
cov_post_HadCM_new_2PIC_SST_D47_T = D47c.OGLS23.T47(D47 = mu_post_HadCM_new_2PIC_SST_D47, sD47 = cov_post_HadCM_new_2PIC_SST_D47, return_covar = True)[1]
cov_post_HadCM_new_1056ppm_SST_D47_T = D47c.OGLS23.T47(D47 = mu_post_HadCM_new_1056ppm_SST_D47, sD47 = cov_post_HadCM_new_1056ppm_SST_D47, return_covar = True)[1]
cov_post_HadCM_old_2PIC_SST_D47_T = D47c.OGLS23.T47(D47 = mu_post_HadCM_old_2PIC_SST_D47, sD47 = cov_post_HadCM_old_2PIC_SST_D47, return_covar = True)[1]
cov_post_HadCM_old_4PIC_SST_D47_T = D47c.OGLS23.T47(D47 = mu_post_HadCM_old_4PIC_SST_D47, sD47 = cov_post_HadCM_old_4PIC_SST_D47, return_covar = True)[1]

# Convert posterior d18Oc and temperature to d18Ow
mu_post_CESM_4PIC_d18Ow_T = mu_post_CESM_4PIC_d18Oc - (20.6 - mu_post_CESM_4PIC_SST_D47_T) / 4.34 + 0.27
mu_post_CESM_2PIC_d18Ow_T = mu_post_CESM_2PIC_d18Oc - (20.6 - mu_post_CESM_2PIC_SST_D47_T) / 4.34 + 0.27
mu_post_HadCM_new_1PIC_d18Ow_T = mu_post_HadCM_new_1PIC_d18Oc - (20.6 - mu_post_HadCM_new_1PIC_SST_D47_T) / 4.34 + 0.27
mu_post_HadCM_new_2PIC_d18Ow_T = mu_post_HadCM_new_2PIC_d18Oc - (20.6 - mu_post_HadCM_new_2PIC_SST_D47_T) / 4.34 + 0.27
mu_post_HadCM_new_1056ppm_d18Ow_T = mu_post_HadCM_new_1056ppm_d18Oc - (20.6 - mu_post_HadCM_new_1056ppm_SST_D47_T) / 4.34 + 0.27
mu_post_HadCM_old_2PIC_d18Ow_T = mu_post_HadCM_old_2PIC_d18Oc - (20.6 - mu_post_HadCM_old_2PIC_SST_D47_T) / 4.34 + 0.27
mu_post_HadCM_old_4PIC_d18Ow_T = mu_post_HadCM_old_4PIC_d18Oc - (20.6 - mu_post_HadCM_old_4PIC_SST_D47_T) / 4.34 + 0.27

# Propagate covariance
cov_post_CESM_4PIC_d18Ow_T = propagate_cov_d18Ow_linear(
    cov_post_CESM_4PIC_d18Oc,
    cov_post_CESM_4PIC_SST_D47_T,
    cross_cov_prior_CESM_4PIC_d18Oc_SST_monthly,
    4.34
)
cov_post_CESM_2PIC_d18Ow_T = propagate_cov_d18Ow_linear(
    cov_post_CESM_2PIC_d18Oc,
    cov_post_CESM_2PIC_SST_D47_T,
    cross_cov_prior_CESM_2PIC_d18Oc_SST_monthly,
    4.34
)
cov_post_HadCM_new_1PIC_d18Ow_T = propagate_cov_d18Ow_linear(
    cov_post_HadCM_new_1PIC_d18Oc,
    cov_post_HadCM_new_1PIC_SST_D47_T,
    cross_cov_prior_HadCM_new_1PIC_d18Oc_SST_monthly,
    4.34
)
cov_post_HadCM_new_2PIC_d18Ow_T = propagate_cov_d18Ow_linear(
    cov_post_HadCM_new_2PIC_d18Oc,
    cov_post_HadCM_new_2PIC_SST_D47_T,
    cross_cov_prior_HadCM_new_2PIC_d18Oc_SST_monthly,
    4.34
)
cov_post_HadCM_new_1056ppm_d18Ow_T = propagate_cov_d18Ow_linear(
    cov_post_HadCM_new_1056ppm_d18Oc,
    cov_post_HadCM_new_1056ppm_SST_D47_T,
    cross_cov_prior_HadCM_new_1056ppm_d18Oc_SST_monthly,
    4.34
)
cov_post_HadCM_old_2PIC_d18Ow_T = propagate_cov_d18Ow_linear(
    cov_post_HadCM_old_2PIC_d18Oc,
    cov_post_HadCM_old_2PIC_SST_D47_T,
    cross_cov_prior_HadCM_old_2PIC_d18Oc_SST_monthly,
    4.34
)
cov_post_HadCM_old_4PIC_d18Ow_T = propagate_cov_d18Ow_linear(
    cov_post_HadCM_old_4PIC_d18Oc,
    cov_post_HadCM_old_4PIC_SST_D47_T,
    cross_cov_prior_HadCM_old_4PIC_d18Oc_SST_monthly,
    4.34
)

# Convert posterior d18Ow to SSS
mu_post_CESM_4PIC_SSS_d18Ow_T = (mu_post_CESM_4PIC_d18Ow_T + 9.300) / 0.274
mu_post_CESM_2PIC_SSS_d18Ow_T = (mu_post_CESM_2PIC_d18Ow_T + 9.300) / 0.274
mu_post_HadCM_new_1PIC_SSS_d18Ow_T = (mu_post_HadCM_new_1PIC_d18Ow_T + 9.300) / 0.274
mu_post_HadCM_new_2PIC_SSS_d18Ow_T = (mu_post_HadCM_new_2PIC_d18Ow_T + 9.300) / 0.274
mu_post_HadCM_new_1056ppm_SSS_d18Ow_T = (mu_post_HadCM_new_1056ppm_d18Ow_T + 9.300) / 0.274
mu_post_HadCM_old_2PIC_SSS_d18Ow_T = (mu_post_HadCM_old_2PIC_d18Ow_T + 9.300) / 0.274
mu_post_HadCM_old_4PIC_SSS_d18Ow_T = (mu_post_HadCM_old_4PIC_d18Ow_T + 9.300) / 0.274

cov_post_CESM_4PIC_SSS_d18Ow_T = cov_post_CESM_4PIC_d18Ow_T / (0.274 ** 2)
cov_post_CESM_2PIC_SSS_d18Ow_T = cov_post_CESM_2PIC_d18Ow_T / (0.274 ** 2)
cov_post_HadCM_new_1PIC_SSS_d18Ow_T = cov_post_HadCM_new_1PIC_d18Ow_T / (0.274 ** 2)
cov_post_HadCM_new_2PIC_SSS_d18Ow_T = cov_post_HadCM_new_2PIC_d18Ow_T / (0.274 ** 2)
cov_post_HadCM_new_1056ppm_SSS_d18Ow_T = cov_post_HadCM_new_1056ppm_d18Ow_T / (0.274 ** 2)
cov_post_HadCM_old_2PIC_SSS_d18Ow_T = cov_post_HadCM_old_2PIC_d18Ow_T / (0.274 ** 2)
cov_post_HadCM_old_4PIC_SSS_d18Ow_T = cov_post_HadCM_old_4PIC_d18Ow_T / (0.274 ** 2)

# Standard deviations in temperature domain
std_prior_CESM_4PIC_SST_D47_monthly_T = np.sqrt(np.diag(cov_prior_CESM_4PIC_SST_D47_monthly_T))
std_prior_CESM_2PIC_SST_D47_monthly_T = np.sqrt(np.diag(cov_prior_CESM_2PIC_SST_D47_monthly_T))
std_prior_HadCM_new_1PIC_SST_D47_monthly_T = np.sqrt(np.diag(cov_prior_HadCM_new_1PIC_SST_D47_monthly_T))
std_prior_HadCM_new_2PIC_SST_D47_monthly_T = np.sqrt(np.diag(cov_prior_HadCM_new_2PIC_SST_D47_monthly_T))
std_prior_HadCM_new_1056ppm_SST_D47_monthly_T = np.sqrt(np.diag(cov_prior_HadCM_new_1056ppm_SST_D47_monthly_T))
std_prior_HadCM_old_2PIC_SST_D47_monthly_T = np.sqrt(np.diag(cov_prior_HadCM_old_2PIC_SST_D47_monthly_T))
std_prior_HadCM_old_4PIC_SST_D47_monthly_T = np.sqrt(np.diag(cov_prior_HadCM_old_4PIC_SST_D47_monthly_T))

std_prior_CESM_4PIC_SSS_d18Ow_monthly_T = np.sqrt(np.diag(cov_prior_CESM_4PIC_SSS_d18Ow_monthly_T))
std_prior_CESM_2PIC_SSS_d18Ow_monthly_T = np.sqrt(np.diag(cov_prior_CESM_2PIC_SSS_d18Ow_monthly_T))
std_prior_HadCM_new_1PIC_SSS_d18Ow_monthly_T = np.sqrt(np.diag(cov_prior_HadCM_new_1PIC_SSS_d18Ow_monthly_T))
std_prior_HadCM_new_2PIC_SSS_d18Ow_monthly_T = np.sqrt(np.diag(cov_prior_HadCM_new_2PIC_SSS_d18Ow_monthly_T))
std_prior_HadCM_new_1056ppm_SSS_d18Ow_monthly_T = np.sqrt(np.diag(cov_prior_HadCM_new_1056ppm_SSS_d18Ow_monthly_T))
std_prior_HadCM_old_2PIC_SSS_d18Ow_monthly_T = np.sqrt(np.diag(cov_prior_HadCM_old_2PIC_SSS_d18Ow_monthly_T))
std_prior_HadCM_old_4PIC_SSS_d18Ow_monthly_T = np.sqrt(np.diag(cov_prior_HadCM_old_4PIC_SSS_d18Ow_monthly_T))

std_likelihood_T = np.sqrt(np.diag(cov_likelihood_T))

std_post_CESM_4PIC_SST_D47_T = np.sqrt(np.diag(cov_post_CESM_4PIC_SST_D47_T))
std_post_CESM_2PIC_SST_D47_T = np.sqrt(np.diag(cov_post_CESM_2PIC_SST_D47_T))
std_post_HadCM_new_1PIC_SST_D47_T = np.sqrt(np.diag(cov_post_HadCM_new_1PIC_SST_D47_T))
std_post_HadCM_new_2PIC_SST_D47_T = np.sqrt(np.diag(cov_post_HadCM_new_2PIC_SST_D47_T))
std_post_HadCM_new_1056ppm_SST_D47_T = np.sqrt(np.diag(cov_post_HadCM_new_1056ppm_SST_D47_T))
std_post_HadCM_old_2PIC_SST_D47_T = np.sqrt(np.diag(cov_post_HadCM_old_2PIC_SST_D47_T))
std_post_HadCM_old_4PIC_SST_D47_T = np.sqrt(np.diag(cov_post_HadCM_old_4PIC_SST_D47_T))

std_post_CESM_4PIC_SSS_d18Ow_T = np.sqrt(np.diag(cov_post_CESM_4PIC_SSS_d18Ow_T))
std_post_CESM_2PIC_SSS_d18Ow_T = np.sqrt(np.diag(cov_post_CESM_2PIC_SSS_d18Ow_T))
std_post_HadCM_new_1PIC_SSS_d18Ow_T = np.sqrt(np.diag(cov_post_HadCM_new_1PIC_SSS_d18Ow_T))
std_post_HadCM_new_2PIC_SSS_d18Ow_T = np.sqrt(np.diag(cov_post_HadCM_new_2PIC_SSS_d18Ow_T))
std_post_HadCM_new_1056ppm_SSS_d18Ow_T = np.sqrt(np.diag(cov_post_HadCM_new_1056ppm_SSS_d18Ow_T))
std_post_HadCM_old_2PIC_SSS_d18Ow_T = np.sqrt(np.diag(cov_post_HadCM_old_2PIC_SSS_d18Ow_T))
std_post_HadCM_old_4PIC_SSS_d18Ow_T = np.sqrt(np.diag(cov_post_HadCM_old_4PIC_SSS_d18Ow_T))

Plot SST and SSS prior and posterior¶

In [77]:
# Initiate plot
fig, axs = plt.subplots(2, 7, figsize=(20, 8), sharex="col", sharey="row")

# Start with DA based on CESM model outcomes with 4x preindustrial pCO2 forcing

# FIRST PANEL: SST Results
# PRIOR
axs[0, 0].plot(months_scale, mu_prior_CESM_4PIC_SST_D47_monthly_T, label='Prior Mean', color='b', marker='o')
axs[0, 0].fill_between(months_scale,
    mu_prior_CESM_4PIC_SST_D47_monthly_T - stats.t.ppf(1 - 0.025, n_models_CESM_4PIC_monthly) * std_prior_CESM_4PIC_SST_D47_monthly_T / np.sqrt(n_models_CESM_4PIC_monthly),
    mu_prior_CESM_4PIC_SST_D47_monthly_T + stats.t.ppf(1 - 0.025, n_models_CESM_4PIC_monthly) * std_prior_CESM_4PIC_SST_D47_monthly_T / np.sqrt(n_models_CESM_4PIC_monthly),
    color='b', alpha=0.2, label='95% Confidence Interval')

# LIKELIHOOD
axs[0, 0].plot(months_scale, mu_likelihood_T, label='Likelihood Mean', color='y', marker='o')
axs[0, 0].fill_between(months_scale,
    mu_likelihood_T - stats.t.ppf(1 - 0.025, n_update_CESM_4PIC_D47) * std_likelihood_T / np.sqrt(n_update_CESM_4PIC_D47),
    mu_likelihood_T + stats.t.ppf(1 - 0.025, n_update_CESM_4PIC_D47) * std_likelihood_T / np.sqrt(n_update_CESM_4PIC_D47),
    color='y', alpha=0.2, label='95% Confidence Interval')

# POSTERIOR
axs[0, 0].plot(months_scale, mu_post_CESM_4PIC_SST_D47_T, label='Posterior Mean', color='r', marker='o')
axs[0, 0].fill_between(months_scale,
    mu_post_CESM_4PIC_SST_D47_T - stats.t.ppf(1 - 0.025, (n_update_CESM_4PIC_D47 + n_models_CESM_4PIC_monthly)) * std_post_CESM_4PIC_SST_D47_T / np.sqrt(n_update_CESM_4PIC_D47 + n_models_CESM_4PIC_monthly),
    mu_post_CESM_4PIC_SST_D47_T + stats.t.ppf(1 - 0.025, (n_update_CESM_4PIC_D47 + n_models_CESM_4PIC_monthly)) * std_post_CESM_4PIC_SST_D47_T / np.sqrt(n_update_CESM_4PIC_D47 + n_models_CESM_4PIC_monthly),
    color='r', alpha=0.2, label='95% Confidence Interval')

# Layout for SST panel
axs[0, 0].set_title('CESM 4x preindustrial pCO2')
axs[0, 0].set_xlabel('Month')
axs[0, 0].set_ylabel('Temperature (°C)')
# axs[0, 0].legend(loc='upper left')
axs[0, 0].grid(True)
axs[0, 0].set_xticks(months_scale, month_names, rotation=45, ha="right")

# SECOND PANEL: SSS Results
# PRIOR
axs[1, 0].plot(months_scale, mu_prior_CESM_4PIC_SSS_d18Ow_monthly_T, label='Prior Mean', color='b', marker='o')
axs[1, 0].fill_between(months_scale,
    mu_prior_CESM_4PIC_SSS_d18Ow_monthly_T - stats.t.ppf(1 - 0.025, n_models_CESM_4PIC_monthly) * std_prior_CESM_4PIC_SSS_d18Ow_monthly_T / np.sqrt(n_models_CESM_4PIC_monthly),
    mu_prior_CESM_4PIC_SSS_d18Ow_monthly_T + stats.t.ppf(1 - 0.025, n_models_CESM_4PIC_monthly) * std_prior_CESM_4PIC_SSS_d18Ow_monthly_T / np.sqrt(n_models_CESM_4PIC_monthly),
    color='b', alpha=0.2, label='95% Confidence Interval')

# LIKELIHOOD
axs[1, 0].plot(months_scale, mu_likelihood_SSS_d18Ow_T, label='Likelihood Mean', color='y', marker='o')
axs[1, 0].fill_between(months_scale,
    mu_likelihood_SSS_d18Ow_T - stats.t.ppf(1 - 0.025, n_update_CESM_4PIC_d18Oc) * std_likelihood_SSS_d18Ow_T / np.sqrt(n_update_CESM_4PIC_d18Oc),
    mu_likelihood_SSS_d18Ow_T + stats.t.ppf(1 - 0.025, n_update_CESM_4PIC_d18Oc) * std_likelihood_SSS_d18Ow_T / np.sqrt(n_update_CESM_4PIC_d18Oc),
    color='y', alpha=0.2, label='95% Confidence Interval')

# POSTERIOR
axs[1, 0].plot(months_scale, mu_post_CESM_4PIC_SSS_d18Ow_T, label='Posterior Mean', color='r', marker='o')
axs[1, 0].fill_between(months_scale,
    mu_post_CESM_4PIC_SSS_d18Ow_T - stats.t.ppf(1 - 0.025, (n_update_CESM_4PIC_d18Oc + n_models_CESM_4PIC_monthly)) * std_post_CESM_4PIC_SSS_d18Ow_T / np.sqrt(n_update_CESM_4PIC_d18Oc + n_models_CESM_4PIC_monthly),
    mu_post_CESM_4PIC_SSS_d18Ow_T + stats.t.ppf(1 - 0.025, (n_update_CESM_4PIC_d18Oc + n_models_CESM_4PIC_monthly)) * std_post_CESM_4PIC_SSS_d18Ow_T / np.sqrt(n_update_CESM_4PIC_d18Oc + n_models_CESM_4PIC_monthly),
    color='r', alpha=0.2, label='95% Confidence Interval')

# Layout for SSS panel
# axs[1, 0].set_title('monthly Sea Surface Salinity (SSS)')
axs[1, 0].set_xlabel('Month')
axs[1, 0].set_ylabel('Salinity (PSU)')
# axs[1, 0].legend(loc='upper left')
axs[1, 0].grid(True)
axs[1, 0].set_xticks(months_scale, month_names, rotation=45, ha="right")

# Next panels similar but for CESM with 2x preindustrial pCO2 forcing

# FIRST PANEL: SST Results for 2x pCO2
# PRIOR
axs[0, 1].plot(months_scale, mu_prior_CESM_2PIC_SST_D47_monthly_T, label='Prior Mean', color='b', marker='o')
axs[0, 1].fill_between(months_scale,
    mu_prior_CESM_2PIC_SST_D47_monthly_T - stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_SST_D47_monthly_T / np.sqrt(n_models_CESM_2PIC_monthly),
    mu_prior_CESM_2PIC_SST_D47_monthly_T + stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_SST_D47_monthly_T / np.sqrt(n_models_CESM_2PIC_monthly),
    color='b', alpha=0.2, label='95% Confidence Interval')

# LIKELIHOOD
axs[0, 1].plot(months_scale, mu_likelihood_T, label='Likelihood Mean', color='y', marker='o')
axs[0, 1].fill_between(months_scale,
    mu_likelihood_T - stats.t.ppf(1 - 0.025, n_update_CESM_2PIC_D47) * std_likelihood_T / np.sqrt(n_update_CESM_2PIC_D47),
    mu_likelihood_T + stats.t.ppf(1 - 0.025, n_update_CESM_2PIC_D47) * std_likelihood_T / np.sqrt(n_update_CESM_2PIC_D47),
    color='y', alpha=0.2, label='95% Confidence Interval')

# POSTERIOR
axs[0, 1].plot(months_scale, mu_post_CESM_2PIC_SST_D47_T, label='Posterior Mean', color='r', marker='o')
axs[0, 1].fill_between(months_scale,
    mu_post_CESM_2PIC_SST_D47_T - stats.t.ppf(1 - 0.025, (n_update_CESM_2PIC_D47 + n_models_CESM_2PIC_monthly)) * std_post_CESM_2PIC_SST_D47_T / np.sqrt(n_update_CESM_2PIC_D47 + n_models_CESM_2PIC_monthly),
    mu_post_CESM_2PIC_SST_D47_T + stats.t.ppf(1 - 0.025, (n_update_CESM_2PIC_D47 + n_models_CESM_2PIC_monthly)) * std_post_CESM_2PIC_SST_D47_T / np.sqrt(n_update_CESM_2PIC_D47 + n_models_CESM_2PIC_monthly),
    color='r', alpha=0.2, label='95% Confidence Interval')

# Layout for SST panel
axs[0, 1].set_title('CESM 2x preindustrial pCO2')
axs[0, 1].set_xlabel('Month')
axs[0, 1].set_ylabel('Temperature (°C)')
# axs[0, 1].legend(loc='upper left')
axs[0, 1].grid(True)
axs[0, 1].set_xticks(months_scale, month_names, rotation=45, ha="right")

# FOURTH PANEL: SSS Results for 2x pCO2
# PRIOR
axs[1, 1].plot(months_scale, mu_prior_CESM_2PIC_SSS_d18Ow_monthly_T, label='Prior Mean', color='b', marker='o')
axs[1, 1].fill_between(months_scale,
    mu_prior_CESM_2PIC_SSS_d18Ow_monthly_T - stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_SSS_d18Ow_monthly_T / np.sqrt(n_models_CESM_2PIC_monthly),
    mu_prior_CESM_2PIC_SSS_d18Ow_monthly_T + stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_SSS_d18Ow_monthly_T / np.sqrt(n_models_CESM_2PIC_monthly),
    color='b', alpha=0.2, label='95% Confidence Interval')

# LIKELIHOOD
axs[1, 1].plot(months_scale, mu_likelihood_SSS_d18Ow_T, label='Likelihood Mean', color='y', marker='o')
axs[1, 1].fill_between(months_scale,
    mu_likelihood_SSS_d18Ow_T - stats.t.ppf(1 - 0.025, n_update_CESM_2PIC_d18Oc) * std_likelihood_SSS_d18Ow_T / np.sqrt(n_update_CESM_2PIC_d18Oc),
    mu_likelihood_SSS_d18Ow_T + stats.t.ppf(1 - 0.025, n_update_CESM_2PIC_d18Oc) * std_likelihood_SSS_d18Ow_T / np.sqrt(n_update_CESM_2PIC_d18Oc),
    color='y', alpha=0.2, label='95% Confidence Interval')

# POSTERIOR
axs[1, 1].plot(months_scale, mu_post_CESM_2PIC_SSS_d18Ow_T, label='Posterior Mean', color='r', marker='o')
axs[1, 1].fill_between(months_scale,
    mu_post_CESM_2PIC_SSS_d18Ow_T - stats.t.ppf(1 - 0.025, (n_update_CESM_2PIC_d18Oc + n_models_CESM_2PIC_monthly)) * std_post_CESM_2PIC_SSS_d18Ow_T / np.sqrt(n_update_CESM_2PIC_d18Oc + n_models_CESM_2PIC_monthly),
    mu_post_CESM_2PIC_SSS_d18Ow_T + stats.t.ppf(1 - 0.025, (n_update_CESM_2PIC_d18Oc + n_models_CESM_2PIC_monthly)) * std_post_CESM_2PIC_SSS_d18Ow_T / np.sqrt(n_update_CESM_2PIC_d18Oc + n_models_CESM_2PIC_monthly),
    color='r', alpha=0.2, label='95% Confidence Interval')

# Layout for SSS panel
# axs[1, 1].set_title('monthly Sea Surface Salinity (SSS)')
axs[1, 1].set_xlabel('Month')
axs[1, 1].set_ylabel('Salinity (PSU)')
# axs[1, 1].legend(loc='upper left')
axs[1, 1].grid(True)
axs[1, 1].set_xticks(months_scale, month_names, rotation=45, ha="right")

# Next panels similar but for HadCM (new) with 1x preindustrial pCO2 forcing

# SST Results for 2x pCO2
# PRIOR
axs[0, 2].plot(months_scale, mu_prior_HadCM_new_1PIC_SST_D47_monthly_T, label='Prior Mean', color='b', marker='o')
axs[0, 2].fill_between(months_scale,
    mu_prior_HadCM_new_1PIC_SST_D47_monthly_T - stats.t.ppf(1 - 0.025, n_models_HadCM_new_1PIC_monthly) * std_prior_HadCM_new_1PIC_SST_D47_monthly_T / np.sqrt(n_models_HadCM_new_1PIC_monthly),
    mu_prior_HadCM_new_1PIC_SST_D47_monthly_T + stats.t.ppf(1 - 0.025, n_models_HadCM_new_1PIC_monthly) * std_prior_HadCM_new_1PIC_SST_D47_monthly_T / np.sqrt(n_models_HadCM_new_1PIC_monthly),
    color='b', alpha=0.2, label='95% Confidence Interval')

# LIKELIHOOD
axs[0, 2].plot(months_scale, mu_likelihood_T, label='Likelihood Mean', color='y', marker='o')
axs[0, 2].fill_between(months_scale,
    mu_likelihood_T - stats.t.ppf(1 - 0.025, n_update_HadCM_new_1PIC_D47) * std_likelihood_T / np.sqrt(n_update_HadCM_new_1PIC_D47),
    mu_likelihood_T + stats.t.ppf(1 - 0.025, n_update_HadCM_new_1PIC_D47) * std_likelihood_T / np.sqrt(n_update_HadCM_new_1PIC_D47),
    color='y', alpha=0.2, label='95% Confidence Interval')

# POSTERIOR
axs[0, 2].plot(months_scale, mu_post_HadCM_new_1PIC_SST_D47_T, label='Posterior Mean', color='r', marker='o')
axs[0, 2].fill_between(months_scale,
    mu_post_HadCM_new_1PIC_SST_D47_T - stats.t.ppf(1 - 0.025, (n_update_HadCM_new_1PIC_D47 + n_models_HadCM_new_1PIC_monthly)) * std_post_HadCM_new_1PIC_SST_D47_T / np.sqrt(n_update_HadCM_new_1PIC_D47 + n_models_HadCM_new_1PIC_monthly),
    mu_post_HadCM_new_1PIC_SST_D47_T + stats.t.ppf(1 - 0.025, (n_update_HadCM_new_1PIC_D47 + n_models_HadCM_new_1PIC_monthly)) * std_post_HadCM_new_1PIC_SST_D47_T / np.sqrt(n_update_HadCM_new_1PIC_D47 + n_models_HadCM_new_1PIC_monthly),
    color='r', alpha=0.2, label='95% Confidence Interval')

# Layout for SST panel
axs[0, 2].set_title('HadCM 1x preindustrial pCO2')
axs[0, 2].set_xlabel('Month')
axs[0, 2].set_ylabel('Temperature (°C)')
# axs[0, 2].legend(loc='upper left')
axs[0, 2].grid(True)
axs[0, 2].set_xticks(months_scale, month_names, rotation=45, ha="right")

# SSS Results for 2x pCO2
# PRIOR
axs[1, 2].plot(months_scale, mu_prior_HadCM_new_1PIC_SSS_d18Ow_monthly_T, label='Prior Mean', color='b', marker='o')
axs[1, 2].fill_between(months_scale,
    mu_prior_HadCM_new_1PIC_SSS_d18Ow_monthly_T - stats.t.ppf(1 - 0.025, n_models_HadCM_new_1PIC_monthly) * std_prior_HadCM_new_1PIC_SSS_d18Ow_monthly_T / np.sqrt(n_models_HadCM_new_1PIC_monthly),
    mu_prior_HadCM_new_1PIC_SSS_d18Ow_monthly_T + stats.t.ppf(1 - 0.025, n_models_HadCM_new_1PIC_monthly) * std_prior_HadCM_new_1PIC_SSS_d18Ow_monthly_T / np.sqrt(n_models_HadCM_new_1PIC_monthly),
    color='b', alpha=0.2, label='95% Confidence Interval')

# LIKELIHOOD
axs[1, 2].plot(months_scale, mu_likelihood_SSS_d18Ow_T, label='Likelihood Mean', color='y', marker='o')
axs[1, 2].fill_between(months_scale,
    mu_likelihood_SSS_d18Ow_T - stats.t.ppf(1 - 0.025, n_update_HadCM_new_1PIC_d18Oc) * std_likelihood_SSS_d18Ow_T / np.sqrt(n_update_HadCM_new_1PIC_d18Oc),
    mu_likelihood_SSS_d18Ow_T + stats.t.ppf(1 - 0.025, n_update_HadCM_new_1PIC_d18Oc) * std_likelihood_SSS_d18Ow_T / np.sqrt(n_update_HadCM_new_1PIC_d18Oc),
    color='y', alpha=0.2, label='95% Confidence Interval')

# POSTERIOR
axs[1, 2].plot(months_scale, mu_post_HadCM_new_1PIC_SSS_d18Ow_T, label='Posterior Mean', color='r', marker='o')
axs[1, 2].fill_between(months_scale,
    mu_post_HadCM_new_1PIC_SSS_d18Ow_T - stats.t.ppf(1 - 0.025, (n_update_HadCM_new_1PIC_d18Oc + n_models_HadCM_new_1PIC_monthly)) * std_post_HadCM_new_1PIC_SSS_d18Ow_T / np.sqrt(n_update_HadCM_new_1PIC_d18Oc + n_models_HadCM_new_1PIC_monthly),
    mu_post_HadCM_new_1PIC_SSS_d18Ow_T + stats.t.ppf(1 - 0.025, (n_update_HadCM_new_1PIC_d18Oc + n_models_HadCM_new_1PIC_monthly)) * std_post_HadCM_new_1PIC_SSS_d18Ow_T / np.sqrt(n_update_HadCM_new_1PIC_d18Oc + n_models_HadCM_new_1PIC_monthly),
    color='r', alpha=0.2, label='95% Confidence Interval')

# Layout for SSS panel
# axs[1, 2].set_title('monthly Sea Surface Salinity (SSS)')
axs[1, 2].set_xlabel('Month')
axs[1, 2].set_ylabel('Salinity (PSU)')
# axs[1, 2].legend(loc='upper left')
axs[1, 2].grid(True)
axs[1, 2].set_xticks(months_scale, month_names, rotation=45, ha="right")

# Next panels similar but for HadCM (new) with 2x preindustrial pCO2 forcing

# SST Results for 2x pCO2
# PRIOR
axs[0, 3].plot(months_scale, mu_prior_HadCM_new_2PIC_SST_D47_monthly_T, label='Prior Mean', color='b', marker='o')
axs[0, 3].fill_between(months_scale,
    mu_prior_HadCM_new_2PIC_SST_D47_monthly_T - stats.t.ppf(1 - 0.025, n_models_HadCM_new_2PIC_monthly) * std_prior_HadCM_new_2PIC_SST_D47_monthly_T / np.sqrt(n_models_HadCM_new_2PIC_monthly),
    mu_prior_HadCM_new_2PIC_SST_D47_monthly_T + stats.t.ppf(1 - 0.025, n_models_HadCM_new_2PIC_monthly) * std_prior_HadCM_new_2PIC_SST_D47_monthly_T / np.sqrt(n_models_HadCM_new_2PIC_monthly),
    color='b', alpha=0.2, label='95% Confidence Interval')

# LIKELIHOOD
axs[0, 3].plot(months_scale, mu_likelihood_T, label='Likelihood Mean', color='y', marker='o')
axs[0, 3].fill_between(months_scale,
    mu_likelihood_T - stats.t.ppf(1 - 0.025, n_update_HadCM_new_2PIC_D47) * std_likelihood_T / np.sqrt(n_update_HadCM_new_2PIC_D47),
    mu_likelihood_T + stats.t.ppf(1 - 0.025, n_update_HadCM_new_2PIC_D47) * std_likelihood_T / np.sqrt(n_update_HadCM_new_2PIC_D47),
    color='y', alpha=0.2, label='95% Confidence Interval')

# POSTERIOR
axs[0, 3].plot(months_scale, mu_post_HadCM_new_2PIC_SST_D47_T, label='Posterior Mean', color='r', marker='o')
axs[0, 3].fill_between(months_scale,
    mu_post_HadCM_new_2PIC_SST_D47_T - stats.t.ppf(1 - 0.025, (n_update_HadCM_new_2PIC_D47 + n_models_HadCM_new_2PIC_monthly)) * std_post_HadCM_new_2PIC_SST_D47_T / np.sqrt(n_update_HadCM_new_2PIC_D47 + n_models_HadCM_new_2PIC_monthly),
    mu_post_HadCM_new_2PIC_SST_D47_T + stats.t.ppf(1 - 0.025, (n_update_HadCM_new_2PIC_D47 + n_models_HadCM_new_2PIC_monthly)) * std_post_HadCM_new_2PIC_SST_D47_T / np.sqrt(n_update_HadCM_new_2PIC_D47 + n_models_HadCM_new_2PIC_monthly),
    color='r', alpha=0.2, label='95% Confidence Interval')

# Layout for SST panel
axs[0, 3].set_title('HadCM 2x preindustrial pCO2')
axs[0, 3].set_xlabel('Month')
axs[0, 3].set_ylabel('Temperature (°C)')
# axs[0, 3].legend(loc='upper left')
axs[0, 3].grid(True)
axs[0, 3].set_xticks(months_scale, month_names, rotation=45, ha="right")

# SSS Results for 2x pCO2
# PRIOR
axs[1, 3].plot(months_scale, mu_prior_HadCM_new_2PIC_SSS_d18Ow_monthly_T, label='Prior Mean', color='b', marker='o')
axs[1, 3].fill_between(months_scale,
    mu_prior_HadCM_new_2PIC_SSS_d18Ow_monthly_T - stats.t.ppf(1 - 0.025, n_models_HadCM_new_2PIC_monthly) * std_prior_HadCM_new_2PIC_SSS_d18Ow_monthly_T / np.sqrt(n_models_HadCM_new_2PIC_monthly),
    mu_prior_HadCM_new_2PIC_SSS_d18Ow_monthly_T + stats.t.ppf(1 - 0.025, n_models_HadCM_new_2PIC_monthly) * std_prior_HadCM_new_2PIC_SSS_d18Ow_monthly_T / np.sqrt(n_models_HadCM_new_2PIC_monthly),
    color='b', alpha=0.2, label='95% Confidence Interval')

# LIKELIHOOD
axs[1, 3].plot(months_scale, mu_likelihood_SSS_d18Ow_T, label='Likelihood Mean', color='y', marker='o')
axs[1, 3].fill_between(months_scale,
    mu_likelihood_SSS_d18Ow_T - stats.t.ppf(1 - 0.025, n_update_HadCM_new_2PIC_d18Oc) * std_likelihood_SSS_d18Ow_T / np.sqrt(n_update_HadCM_new_2PIC_d18Oc),
    mu_likelihood_SSS_d18Ow_T + stats.t.ppf(1 - 0.025, n_update_HadCM_new_2PIC_d18Oc) * std_likelihood_SSS_d18Ow_T / np.sqrt(n_update_HadCM_new_2PIC_d18Oc),
    color='y', alpha=0.2, label='95% Confidence Interval')

# POSTERIOR
axs[1, 3].plot(months_scale, mu_post_HadCM_new_2PIC_SSS_d18Ow_T, label='Posterior Mean', color='r', marker='o')
axs[1, 3].fill_between(months_scale,
    mu_post_HadCM_new_2PIC_SSS_d18Ow_T - stats.t.ppf(1 - 0.025, (n_update_HadCM_new_2PIC_d18Oc + n_models_HadCM_new_2PIC_monthly)) * std_post_HadCM_new_2PIC_SSS_d18Ow_T / np.sqrt(n_update_HadCM_new_2PIC_d18Oc + n_models_HadCM_new_2PIC_monthly),
    mu_post_HadCM_new_2PIC_SSS_d18Ow_T + stats.t.ppf(1 - 0.025, (n_update_HadCM_new_2PIC_d18Oc + n_models_HadCM_new_2PIC_monthly)) * std_post_HadCM_new_2PIC_SSS_d18Ow_T / np.sqrt(n_update_HadCM_new_2PIC_d18Oc + n_models_HadCM_new_2PIC_monthly),
    color='r', alpha=0.2, label='95% Confidence Interval')

# Layout for SSS panel
# axs[1, 3].set_title('monthly Sea Surface Salinity (SSS)')
axs[1, 3].set_xlabel('Month')
axs[1, 3].set_ylabel('Salinity (PSU)')
# axs[1, 3].legend(loc='upper left')
axs[1, 3].grid(True)
axs[1, 3].set_xticks(months_scale, month_names, rotation=45, ha="right")


# Next panels similar but for HadCM (new) with 1056 ppm pCO2 forcing

# SST Results for 2x pCO2
# PRIOR
axs[0, 4].plot(months_scale, mu_prior_HadCM_new_1056ppm_SST_D47_monthly_T, label='Prior Mean', color='b', marker='o')
axs[0, 4].fill_between(months_scale,
    mu_prior_HadCM_new_1056ppm_SST_D47_monthly_T - stats.t.ppf(1 - 0.025, n_models_HadCM_new_1056ppm_monthly) * std_prior_HadCM_new_1056ppm_SST_D47_monthly_T / np.sqrt(n_models_HadCM_new_1056ppm_monthly),
    mu_prior_HadCM_new_1056ppm_SST_D47_monthly_T + stats.t.ppf(1 - 0.025, n_models_HadCM_new_1056ppm_monthly) * std_prior_HadCM_new_1056ppm_SST_D47_monthly_T / np.sqrt(n_models_HadCM_new_1056ppm_monthly),
    color='b', alpha=0.2, label='95% Confidence Interval')

# LIKELIHOOD
axs[0, 4].plot(months_scale, mu_likelihood_T, label='Likelihood Mean', color='y', marker='o')
axs[0, 4].fill_between(months_scale,
    mu_likelihood_T - stats.t.ppf(1 - 0.025, n_update_HadCM_new_1056ppm_D47) * std_likelihood_T / np.sqrt(n_update_HadCM_new_1056ppm_D47),
    mu_likelihood_T + stats.t.ppf(1 - 0.025, n_update_HadCM_new_1056ppm_D47) * std_likelihood_T / np.sqrt(n_update_HadCM_new_1056ppm_D47),
    color='y', alpha=0.2, label='95% Confidence Interval')

# POSTERIOR
axs[0, 4].plot(months_scale, mu_post_HadCM_new_1056ppm_SST_D47_T, label='Posterior Mean', color='r', marker='o')
axs[0, 4].fill_between(months_scale,
    mu_post_HadCM_new_1056ppm_SST_D47_T - stats.t.ppf(1 - 0.025, (n_update_HadCM_new_1056ppm_D47 + n_models_HadCM_new_1056ppm_monthly)) * std_post_HadCM_new_1056ppm_SST_D47_T / np.sqrt(n_update_HadCM_new_1056ppm_D47 + n_models_HadCM_new_1056ppm_monthly),
    mu_post_HadCM_new_1056ppm_SST_D47_T + stats.t.ppf(1 - 0.025, (n_update_HadCM_new_1056ppm_D47 + n_models_HadCM_new_1056ppm_monthly)) * std_post_HadCM_new_1056ppm_SST_D47_T / np.sqrt(n_update_HadCM_new_1056ppm_D47 + n_models_HadCM_new_1056ppm_monthly),
    color='r', alpha=0.2, label='95% Confidence Interval')

# Layout for SST panel
axs[0, 4].set_title('HadCM (new) 1056 ppm pCO2')
axs[0, 4].set_xlabel('Month')
axs[0, 4].set_ylabel('Temperature (°C)')
# axs[0, 4].legend(loc='upper left')
axs[0, 4].grid(True)
axs[0, 4].set_xticks(months_scale, month_names, rotation=45, ha="right")

# SSS Results for 2x pCO2
# PRIOR
axs[1, 4].plot(months_scale, mu_prior_HadCM_new_1056ppm_SSS_d18Ow_monthly_T, label='Prior Mean', color='b', marker='o')
axs[1, 4].fill_between(months_scale,
    mu_prior_HadCM_new_1056ppm_SSS_d18Ow_monthly_T - stats.t.ppf(1 - 0.025, n_models_HadCM_new_1056ppm_monthly) * std_prior_HadCM_new_1056ppm_SSS_d18Ow_monthly_T / np.sqrt(n_models_HadCM_new_1056ppm_monthly),
    mu_prior_HadCM_new_1056ppm_SSS_d18Ow_monthly_T + stats.t.ppf(1 - 0.025, n_models_HadCM_new_1056ppm_monthly) * std_prior_HadCM_new_1056ppm_SSS_d18Ow_monthly_T / np.sqrt(n_models_HadCM_new_1056ppm_monthly),
    color='b', alpha=0.2, label='95% Confidence Interval')

# LIKELIHOOD
axs[1, 4].plot(months_scale, mu_likelihood_SSS_d18Ow_T, label='Likelihood Mean', color='y', marker='o')
axs[1, 4].fill_between(months_scale,
    mu_likelihood_SSS_d18Ow_T - stats.t.ppf(1 - 0.025, n_update_HadCM_new_1056ppm_d18Oc) * std_likelihood_SSS_d18Ow_T / np.sqrt(n_update_HadCM_new_1056ppm_d18Oc),
    mu_likelihood_SSS_d18Ow_T + stats.t.ppf(1 - 0.025, n_update_HadCM_new_1056ppm_d18Oc) * std_likelihood_SSS_d18Ow_T / np.sqrt(n_update_HadCM_new_1056ppm_d18Oc),
    color='y', alpha=0.2, label='95% Confidence Interval')

# POSTERIOR
axs[1, 4].plot(months_scale, mu_post_HadCM_new_1056ppm_SSS_d18Ow_T, label='Posterior Mean', color='r', marker='o')
axs[1, 4].fill_between(months_scale,
    mu_post_HadCM_new_1056ppm_SSS_d18Ow_T - stats.t.ppf(1 - 0.025, (n_update_HadCM_new_1056ppm_d18Oc + n_models_HadCM_new_1056ppm_monthly)) * std_post_HadCM_new_1056ppm_SSS_d18Ow_T / np.sqrt(n_update_HadCM_new_1056ppm_d18Oc + n_models_HadCM_new_1056ppm_monthly),
    mu_post_HadCM_new_1056ppm_SSS_d18Ow_T + stats.t.ppf(1 - 0.025, (n_update_HadCM_new_1056ppm_d18Oc + n_models_HadCM_new_1056ppm_monthly)) * std_post_HadCM_new_1056ppm_SSS_d18Ow_T / np.sqrt(n_update_HadCM_new_1056ppm_d18Oc + n_models_HadCM_new_1056ppm_monthly),
    color='r', alpha=0.2, label='95% Confidence Interval')

# Layout for SSS panel
# axs[1, 4].set_title('monthly Sea Surface Salinity (SSS)')
axs[1, 4].set_xlabel('Month')
axs[1, 4].set_ylabel('Salinity (PSU)')
# axs[1, 4].legend(loc='upper left')
axs[1, 4].grid(True)
axs[1, 4].set_xticks(months_scale, month_names, rotation=45, ha="right")

# Next panels similar but for HadCM (old) with 2x preindustrial pCO2 forcing

# SST Results for 2x pCO2
# PRIOR
axs[0, 5].plot(months_scale, mu_prior_HadCM_old_2PIC_SST_D47_monthly_T, label='Prior Mean', color='b', marker='o')
axs[0, 5].fill_between(months_scale,
    mu_prior_HadCM_old_2PIC_SST_D47_monthly_T - stats.t.ppf(1 - 0.025, n_models_HadCM_old_2PIC_monthly) * std_prior_HadCM_old_2PIC_SST_D47_monthly_T / np.sqrt(n_models_HadCM_old_2PIC_monthly),
    mu_prior_HadCM_old_2PIC_SST_D47_monthly_T + stats.t.ppf(1 - 0.025, n_models_HadCM_old_2PIC_monthly) * std_prior_HadCM_old_2PIC_SST_D47_monthly_T / np.sqrt(n_models_HadCM_old_2PIC_monthly),
    color='b', alpha=0.2, label='95% Confidence Interval')

# LIKELIHOOD
axs[0, 5].plot(months_scale, mu_likelihood_T, label='Likelihood Mean', color='y', marker='o')
axs[0, 5].fill_between(months_scale,
    mu_likelihood_T - stats.t.ppf(1 - 0.025, n_update_HadCM_old_2PIC_D47) * std_likelihood_T / np.sqrt(n_update_HadCM_old_2PIC_D47),
    mu_likelihood_T + stats.t.ppf(1 - 0.025, n_update_HadCM_old_2PIC_D47) * std_likelihood_T / np.sqrt(n_update_HadCM_old_2PIC_D47),
    color='y', alpha=0.2, label='95% Confidence Interval')

# POSTERIOR
axs[0, 5].plot(months_scale, mu_post_HadCM_old_2PIC_SST_D47_T, label='Posterior Mean', color='r', marker='o')
axs[0, 5].fill_between(months_scale,
    mu_post_HadCM_old_2PIC_SST_D47_T - stats.t.ppf(1 - 0.025, (n_update_HadCM_old_2PIC_D47 + n_models_HadCM_old_2PIC_monthly)) * std_post_HadCM_old_2PIC_SST_D47_T / np.sqrt(n_update_HadCM_old_2PIC_D47 + n_models_HadCM_old_2PIC_monthly),
    mu_post_HadCM_old_2PIC_SST_D47_T + stats.t.ppf(1 - 0.025, (n_update_HadCM_old_2PIC_D47 + n_models_HadCM_old_2PIC_monthly)) * std_post_HadCM_old_2PIC_SST_D47_T / np.sqrt(n_update_HadCM_old_2PIC_D47 + n_models_HadCM_old_2PIC_monthly),
    color='r', alpha=0.2, label='95% Confidence Interval')

# Layout for SST panel
axs[0, 5].set_title('HadCM (old) 2x preindustrial pCO2')
axs[0, 5].set_xlabel('Month')
axs[0, 5].set_ylabel('Temperature (°C)')
# axs[0, 5].legend(loc='upper left')
axs[0, 5].grid(True)
axs[0, 5].set_xticks(months_scale, month_names, rotation=45, ha="right")

# SSS Results for 2x pCO2
# PRIOR
axs[1, 5].plot(months_scale, mu_prior_HadCM_old_2PIC_SSS_d18Ow_monthly_T, label='Prior Mean', color='b', marker='o')
axs[1, 5].fill_between(months_scale,
    mu_prior_HadCM_old_2PIC_SSS_d18Ow_monthly_T - stats.t.ppf(1 - 0.025, n_models_HadCM_old_2PIC_monthly) * std_prior_HadCM_old_2PIC_SSS_d18Ow_monthly_T / np.sqrt(n_models_HadCM_old_2PIC_monthly),
    mu_prior_HadCM_old_2PIC_SSS_d18Ow_monthly_T + stats.t.ppf(1 - 0.025, n_models_HadCM_old_2PIC_monthly) * std_prior_HadCM_old_2PIC_SSS_d18Ow_monthly_T / np.sqrt(n_models_HadCM_old_2PIC_monthly),
    color='b', alpha=0.2, label='95% Confidence Interval')

# LIKELIHOOD
axs[1, 5].plot(months_scale, mu_likelihood_SSS_d18Ow_T, label='Likelihood Mean', color='y', marker='o')
axs[1, 5].fill_between(months_scale,
    mu_likelihood_SSS_d18Ow_T - stats.t.ppf(1 - 0.025, n_update_HadCM_old_2PIC_d18Oc) * std_likelihood_SSS_d18Ow_T / np.sqrt(n_update_HadCM_old_2PIC_d18Oc),
    mu_likelihood_SSS_d18Ow_T + stats.t.ppf(1 - 0.025, n_update_HadCM_old_2PIC_d18Oc) * std_likelihood_SSS_d18Ow_T / np.sqrt(n_update_HadCM_old_2PIC_d18Oc),
    color='y', alpha=0.2, label='95% Confidence Interval')

# POSTERIOR
axs[1, 5].plot(months_scale, mu_post_HadCM_old_2PIC_SSS_d18Ow_T, label='Posterior Mean', color='r', marker='o')
axs[1, 5].fill_between(months_scale,
    mu_post_HadCM_old_2PIC_SSS_d18Ow_T - stats.t.ppf(1 - 0.025, (n_update_HadCM_old_2PIC_d18Oc + n_models_HadCM_old_2PIC_monthly)) * std_post_HadCM_old_2PIC_SSS_d18Ow_T / np.sqrt(n_update_HadCM_old_2PIC_d18Oc + n_models_HadCM_old_2PIC_monthly),
    mu_post_HadCM_old_2PIC_SSS_d18Ow_T + stats.t.ppf(1 - 0.025, (n_update_HadCM_old_2PIC_d18Oc + n_models_HadCM_old_2PIC_monthly)) * std_post_HadCM_old_2PIC_SSS_d18Ow_T / np.sqrt(n_update_HadCM_old_2PIC_d18Oc + n_models_HadCM_old_2PIC_monthly),
    color='r', alpha=0.2, label='95% Confidence Interval')

# Layout for SSS panel
# axs[1, 5].set_title('monthly Sea Surface Salinity (SSS)')
axs[1, 5].set_xlabel('Month')
axs[1, 5].set_ylabel('Salinity (PSU)')
# axs[1, 5].legend(loc='upper left')
axs[1, 5].grid(True)
axs[1, 5].set_xticks(months_scale, month_names, rotation=45, ha="right")


# Next panels similar but for HadCM (old) with 2x preindustrial pCO2 forcing

# SST Results for 2x pCO2
# PRIOR
axs[0, 6].plot(months_scale, mu_prior_HadCM_old_4PIC_SST_D47_monthly_T, label='Prior Mean', color='b', marker='o')
axs[0, 6].fill_between(months_scale,
    mu_prior_HadCM_old_4PIC_SST_D47_monthly_T - stats.t.ppf(1 - 0.025, n_models_HadCM_old_4PIC_monthly) * std_prior_HadCM_old_4PIC_SST_D47_monthly_T / np.sqrt(n_models_HadCM_old_4PIC_monthly),
    mu_prior_HadCM_old_4PIC_SST_D47_monthly_T + stats.t.ppf(1 - 0.025, n_models_HadCM_old_4PIC_monthly) * std_prior_HadCM_old_4PIC_SST_D47_monthly_T / np.sqrt(n_models_HadCM_old_4PIC_monthly),
    color='b', alpha=0.2, label='95% Confidence Interval')

# LIKELIHOOD
axs[0, 6].plot(months_scale, mu_likelihood_T, label='Likelihood Mean', color='y', marker='o')
axs[0, 6].fill_between(months_scale,
    mu_likelihood_T - stats.t.ppf(1 - 0.025, n_update_HadCM_old_4PIC_D47) * std_likelihood_T / np.sqrt(n_update_HadCM_old_4PIC_D47),
    mu_likelihood_T + stats.t.ppf(1 - 0.025, n_update_HadCM_old_4PIC_D47) * std_likelihood_T / np.sqrt(n_update_HadCM_old_4PIC_D47),
    color='y', alpha=0.2, label='95% Confidence Interval')

# POSTERIOR
axs[0, 6].plot(months_scale, mu_post_HadCM_old_4PIC_SST_D47_T, label='Posterior Mean', color='r', marker='o')
axs[0, 6].fill_between(months_scale,
    mu_post_HadCM_old_4PIC_SST_D47_T - stats.t.ppf(1 - 0.025, (n_update_HadCM_old_4PIC_D47 + n_models_HadCM_old_4PIC_monthly)) * std_post_HadCM_old_4PIC_SST_D47_T / np.sqrt(n_update_HadCM_old_4PIC_D47 + n_models_HadCM_old_4PIC_monthly),
    mu_post_HadCM_old_4PIC_SST_D47_T + stats.t.ppf(1 - 0.025, (n_update_HadCM_old_4PIC_D47 + n_models_HadCM_old_4PIC_monthly)) * std_post_HadCM_old_4PIC_SST_D47_T / np.sqrt(n_update_HadCM_old_4PIC_D47 + n_models_HadCM_old_4PIC_monthly),
    color='r', alpha=0.2, label='95% Confidence Interval')

# Layout for SST panel
axs[0, 6].set_title('HadCM (old) 4x preindustrial pCO2')
axs[0, 6].set_xlabel('Month')
axs[0, 6].set_ylabel('Temperature (°C)')
axs[0, 6].legend(loc='upper left')
axs[0, 6].grid(True)
axs[0, 6].set_xticks(months_scale, month_names, rotation=45, ha="right")

# SSS Results for 2x pCO2
# PRIOR
axs[1, 6].plot(months_scale, mu_prior_HadCM_old_4PIC_SSS_d18Ow_monthly_T, label='Prior Mean', color='b', marker='o')
axs[1, 6].fill_between(months_scale,
    mu_prior_HadCM_old_4PIC_SSS_d18Ow_monthly_T - stats.t.ppf(1 - 0.025, n_models_HadCM_old_4PIC_monthly) * std_prior_HadCM_old_4PIC_SSS_d18Ow_monthly_T / np.sqrt(n_models_HadCM_old_4PIC_monthly),
    mu_prior_HadCM_old_4PIC_SSS_d18Ow_monthly_T + stats.t.ppf(1 - 0.025, n_models_HadCM_old_4PIC_monthly) * std_prior_HadCM_old_4PIC_SSS_d18Ow_monthly_T / np.sqrt(n_models_HadCM_old_4PIC_monthly),
    color='b', alpha=0.2, label='95% Confidence Interval')

# LIKELIHOOD
axs[1, 6].plot(months_scale, mu_likelihood_SSS_d18Ow_T, label='Likelihood Mean', color='y', marker='o')
axs[1, 6].fill_between(months_scale,
    mu_likelihood_SSS_d18Ow_T - stats.t.ppf(1 - 0.025, n_update_HadCM_old_4PIC_d18Oc) * std_likelihood_SSS_d18Ow_T / np.sqrt(n_update_HadCM_old_4PIC_d18Oc),
    mu_likelihood_SSS_d18Ow_T + stats.t.ppf(1 - 0.025, n_update_HadCM_old_4PIC_d18Oc) * std_likelihood_SSS_d18Ow_T / np.sqrt(n_update_HadCM_old_4PIC_d18Oc),
    color='y', alpha=0.2, label='95% Confidence Interval')

# POSTERIOR
axs[1, 6].plot(months_scale, mu_post_HadCM_old_4PIC_SSS_d18Ow_T, label='Posterior Mean', color='r', marker='o')
axs[1, 6].fill_between(months_scale,
    mu_post_HadCM_old_4PIC_SSS_d18Ow_T - stats.t.ppf(1 - 0.025, (n_update_HadCM_old_4PIC_d18Oc + n_models_HadCM_old_4PIC_monthly)) * std_post_HadCM_old_4PIC_SSS_d18Ow_T / np.sqrt(n_update_HadCM_old_4PIC_d18Oc + n_models_HadCM_old_4PIC_monthly),
    mu_post_HadCM_old_4PIC_SSS_d18Ow_T + stats.t.ppf(1 - 0.025, (n_update_HadCM_old_4PIC_d18Oc + n_models_HadCM_old_4PIC_monthly)) * std_post_HadCM_old_4PIC_SSS_d18Ow_T / np.sqrt(n_update_HadCM_old_4PIC_d18Oc + n_models_HadCM_old_4PIC_monthly),
    color='r', alpha=0.2, label='95% Confidence Interval')

# Layout for SSS panel
# axs[1, 6].set_title('monthly Sea Surface Salinity (SSS)')
axs[1, 6].set_xlabel('Month')
axs[1, 6].set_ylabel('Salinity (PSU)')
axs[1, 6].legend(loc='upper left')
axs[1, 6].grid(True)
axs[1, 6].set_xticks(months_scale, month_names, rotation=45, ha="right")

# Shared x-axis labels
plt.xticks(months_scale, month_names, rotation=45, ha="right")
plt.suptitle('Seasonal Sea Surface Temperature (SST) and Sea Surface Salinity (SSS) outcomes for all model scenarios', fontsize=16)
plt.tight_layout()
plt.show()
No description has been provided for this image

Execute SAT and precipitation error propagation for all model scenarios¶

In [78]:
# Convert posterior D47 to temp
mu_post_CESM_2PIC_SAT_D47_T = D47c.OGLS23.T47(D47 = mu_post_CESM_2PIC_SAT_D47, sD47 = cov_post_CESM_2PIC_SAT_D47, return_covar = True)[0]
mu_post_CESM_4PIC_SAT_D47_T = D47c.OGLS23.T47(D47 = mu_post_CESM_4PIC_SAT_D47, sD47 = cov_post_CESM_4PIC_SAT_D47, return_covar = True)[0]
mu_post_HadCM_new_1PIC_SAT_D47_T = D47c.OGLS23.T47(D47 = mu_post_HadCM_new_1PIC_SAT_D47, sD47 = cov_post_HadCM_new_1PIC_SAT_D47, return_covar = True)[0]
mu_post_HadCM_new_2PIC_SAT_D47_T = D47c.OGLS23.T47(D47 = mu_post_HadCM_new_2PIC_SAT_D47, sD47 = cov_post_HadCM_new_2PIC_SAT_D47, return_covar = True)[0]
mu_post_HadCM_new_1056ppm_SAT_D47_T = D47c.OGLS23.T47(D47 = mu_post_HadCM_new_1056ppm_SAT_D47, sD47 = cov_post_HadCM_new_1056ppm_SAT_D47, return_covar = True)[0]
mu_post_HadCM_old_2PIC_SAT_D47_T = D47c.OGLS23.T47(D47 = mu_post_HadCM_old_2PIC_SAT_D47, sD47 = cov_post_HadCM_old_2PIC_SAT_D47, return_covar = True)[0]
mu_post_HadCM_old_4PIC_SAT_D47_T = D47c.OGLS23.T47(D47 = mu_post_HadCM_old_4PIC_SAT_D47, sD47 = cov_post_HadCM_old_4PIC_SAT_D47, return_covar = True)[0]

cov_post_CESM_2PIC_SAT_D47_T = D47c.OGLS23.T47(D47 = mu_post_CESM_2PIC_SAT_D47, sD47 = cov_post_CESM_2PIC_SAT_D47, return_covar = True)[1]
cov_post_CESM_4PIC_SAT_D47_T = D47c.OGLS23.T47(D47 = mu_post_CESM_4PIC_SAT_D47, sD47 = cov_post_CESM_4PIC_SAT_D47, return_covar = True)[1]
cov_post_HadCM_new_1PIC_SAT_D47_T = D47c.OGLS23.T47(D47 = mu_post_HadCM_new_1PIC_SAT_D47, sD47 = cov_post_HadCM_new_1PIC_SAT_D47, return_covar = True)[1]
cov_post_HadCM_new_2PIC_SAT_D47_T = D47c.OGLS23.T47(D47 = mu_post_HadCM_new_2PIC_SAT_D47, sD47 = cov_post_HadCM_new_2PIC_SAT_D47, return_covar = True)[1]
cov_post_HadCM_new_1056ppm_SAT_D47_T = D47c.OGLS23.T47(D47 = mu_post_HadCM_new_1056ppm_SAT_D47, sD47 = cov_post_HadCM_new_1056ppm_SAT_D47, return_covar = True)[1]
cov_post_HadCM_old_2PIC_SAT_D47_T = D47c.OGLS23.T47(D47 = mu_post_HadCM_old_2PIC_SAT_D47, sD47 = cov_post_HadCM_old_2PIC_SAT_D47, return_covar = True)[1]
cov_post_HadCM_old_4PIC_SAT_D47_T = D47c.OGLS23.T47(D47 = mu_post_HadCM_old_4PIC_SAT_D47, sD47 = cov_post_HadCM_old_4PIC_SAT_D47, return_covar = True)[1]

# Convert posterior SAT-D47 back to temperature
std_post_CESM_2PIC_SAT_D47_T = np.nan_to_num(np.sqrt(np.diag(cov_post_CESM_2PIC_SAT_D47_T)))
std_post_CESM_4PIC_SAT_D47_T = np.nan_to_num(np.sqrt(np.diag(cov_post_CESM_4PIC_SAT_D47_T)))
std_post_HadCM_new_1PIC_SAT_D47_T = np.nan_to_num(np.sqrt(np.diag(cov_post_HadCM_new_1PIC_SAT_D47_T)))
std_post_HadCM_new_2PIC_SAT_D47_T = np.nan_to_num(np.sqrt(np.diag(cov_post_HadCM_new_2PIC_SAT_D47_T)))
std_post_HadCM_new_1056ppm_SAT_D47_T = np.nan_to_num(np.sqrt(np.diag(cov_post_HadCM_new_1056ppm_SAT_D47_T)))
std_post_HadCM_old_2PIC_SAT_D47_T = np.nan_to_num(np.sqrt(np.diag(cov_post_HadCM_old_2PIC_SAT_D47_T)))
std_post_HadCM_old_4PIC_SAT_D47_T = np.nan_to_num(np.sqrt(np.diag(cov_post_HadCM_old_4PIC_SAT_D47_T)))

# Calculate standard deviations for precipitation posteriors
std_post_CESM_2PIC_precip = np.nan_to_num(np.sqrt(np.diag(cov_post_CESM_2PIC_precip)))
std_post_CESM_4PIC_precip = np.nan_to_num(np.sqrt(np.diag(cov_post_CESM_4PIC_precip)))
std_post_HadCM_new_1PIC_precip = np.nan_to_num(np.sqrt(np.diag(cov_post_HadCM_new_1PIC_precip)))
std_post_HadCM_new_2PIC_precip = np.nan_to_num(np.sqrt(np.diag(cov_post_HadCM_new_2PIC_precip)))
std_post_HadCM_new_1056ppm_precip = np.nan_to_num(np.sqrt(np.diag(cov_post_HadCM_new_1056ppm_precip)))
std_post_HadCM_old_2PIC_precip = np.nan_to_num(np.sqrt(np.diag(cov_post_HadCM_old_2PIC_precip)))
std_post_HadCM_old_4PIC_precip = np.nan_to_num(np.sqrt(np.diag(cov_post_HadCM_old_4PIC_precip)))

Plot SAT and precipitation prior and posterior¶

In [79]:
# Initiate plot
fig, axs = plt.subplots(2, 7, figsize=(20, 8), sharex="col", sharey="row")

# Start with DA based on CESM model outcomes with 4x preindustrial pCO2 forcing

# FIRST PANEL: SAT Results
# PRIOR
axs[0, 0].plot(months_scale, mu_prior_CESM_4PIC_SAT_monthly, label='Prior Mean', color='b', marker='o')
axs[0, 0].fill_between(months_scale,
    mu_prior_CESM_4PIC_SAT_monthly - stats.t.ppf(1 - 0.025, n_models_CESM_4PIC_monthly) * std_prior_CESM_4PIC_SAT_monthly / np.sqrt(n_models_CESM_4PIC_monthly),
    mu_prior_CESM_4PIC_SAT_monthly + stats.t.ppf(1 - 0.025, n_models_CESM_4PIC_monthly) * std_prior_CESM_4PIC_SAT_monthly / np.sqrt(n_models_CESM_4PIC_monthly),
    color='b', alpha=0.2, label='95% Confidence Interval')

# LIKELIHOOD
axs[0, 0].plot(months_scale, mu_likelihood_T, label='Likelihood Mean', color='y', marker='o')
axs[0, 0].fill_between(months_scale,
    mu_likelihood_T - stats.t.ppf(1 - 0.025, n_update_CESM_4PIC_D47) * std_likelihood_T / np.sqrt(n_update_CESM_4PIC_D47),
    mu_likelihood_T + stats.t.ppf(1 - 0.025, n_update_CESM_4PIC_D47) * std_likelihood_T / np.sqrt(n_update_CESM_4PIC_D47),
    color='y', alpha=0.2, label='95% Confidence Interval')

# POSTERIOR
axs[0, 0].plot(months_scale, mu_post_CESM_4PIC_SAT_D47_T, label='Posterior Mean', color='r', marker='o')
axs[0, 0].fill_between(months_scale,
    mu_post_CESM_4PIC_SAT_D47_T - stats.t.ppf(1 - 0.025, (n_update_CESM_4PIC_D47 + n_models_CESM_4PIC_monthly)) * std_post_CESM_4PIC_SAT_D47_T / np.sqrt(n_update_CESM_4PIC_D47 + n_models_CESM_4PIC_monthly),
    mu_post_CESM_4PIC_SAT_D47_T + stats.t.ppf(1 - 0.025, (n_update_CESM_4PIC_D47 + n_models_CESM_4PIC_monthly)) * std_post_CESM_4PIC_SAT_D47_T / np.sqrt(n_update_CESM_4PIC_D47 + n_models_CESM_4PIC_monthly),
    color='r', alpha=0.2, label='95% Confidence Interval')

# Layout for SAT panel
axs[0, 0].set_title('CESM 4x preindustrial pCO2')
axs[0, 0].set_xlabel('Month')
axs[0, 0].set_ylabel('Surface Air Temperature (°C)')
# axs[0, 0].legend(loc='upper left')
axs[0, 0].grid(True)
axs[0, 0].set_xticks(months_scale, month_names, rotation=45, ha="right")

# SECOND PANEL: precip Results
# PRIOR
axs[1, 0].plot(months_scale, mu_prior_CESM_4PIC_precip_monthly, label='Prior Mean', color='b', marker='o')
axs[1, 0].fill_between(months_scale,
    mu_prior_CESM_4PIC_precip_monthly - stats.t.ppf(1 - 0.025, n_models_CESM_4PIC_monthly) * std_prior_CESM_4PIC_precip_monthly / np.sqrt(n_models_CESM_4PIC_monthly),
    mu_prior_CESM_4PIC_precip_monthly + stats.t.ppf(1 - 0.025, n_models_CESM_4PIC_monthly) * std_prior_CESM_4PIC_precip_monthly / np.sqrt(n_models_CESM_4PIC_monthly),
    color='b', alpha=0.2, label='95% Confidence Interval')

# POSTERIOR
axs[1, 0].plot(months_scale, mu_post_CESM_4PIC_precip, label='Posterior Mean', color='r', marker='o')
axs[1, 0].fill_between(months_scale,
    mu_post_CESM_4PIC_precip - stats.t.ppf(1 - 0.025, (n_update_CESM_4PIC_d18Oc + n_models_CESM_4PIC_monthly)) * std_post_CESM_4PIC_precip / np.sqrt(n_update_CESM_4PIC_d18Oc + n_models_CESM_4PIC_monthly),
    mu_post_CESM_4PIC_precip + stats.t.ppf(1 - 0.025, (n_update_CESM_4PIC_d18Oc + n_models_CESM_4PIC_monthly)) * std_post_CESM_4PIC_precip / np.sqrt(n_update_CESM_4PIC_d18Oc + n_models_CESM_4PIC_monthly),
    color='r', alpha=0.2, label='95% Confidence Interval')

# Layout for precip panel
# axs[1, 0].set_title('monthly Sea Surface Salinity (precip)')
axs[1, 0].set_xlabel('Month')
axs[1, 0].set_ylabel('Precipitation (mm/day)')
# axs[1, 0].legend(loc='upper left')
axs[1, 0].grid(True)
axs[1, 0].set_xticks(months_scale, month_names, rotation=45, ha="right")

# Next panels similar but for CESM with 2x preindustrial pCO2 forcing

# FIRST PANEL: SAT Results
# PRIOR
axs[0, 1].plot(months_scale, mu_prior_CESM_2PIC_SAT_monthly, label='Prior Mean', color='b', marker='o')
axs[0, 1].fill_between(months_scale,
    mu_prior_CESM_2PIC_SAT_monthly - stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_SAT_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
    mu_prior_CESM_2PIC_SAT_monthly + stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_SAT_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
    color='b', alpha=0.2, label='95% Confidence Interval')

# LIKELIHOOD
axs[0, 1].plot(months_scale, mu_likelihood_T, label='Likelihood Mean', color='y', marker='o')
axs[0, 1].fill_between(months_scale,
    mu_likelihood_T - stats.t.ppf(1 - 0.025, n_update_CESM_2PIC_D47) * std_likelihood_T / np.sqrt(n_update_CESM_2PIC_D47),
    mu_likelihood_T + stats.t.ppf(1 - 0.025, n_update_CESM_2PIC_D47) * std_likelihood_T / np.sqrt(n_update_CESM_2PIC_D47),
    color='y', alpha=0.2, label='95% Confidence Interval')

# POSTERIOR
axs[0, 1].plot(months_scale, mu_post_CESM_2PIC_SAT_D47_T, label='Posterior Mean', color='r', marker='o')
axs[0, 1].fill_between(months_scale,
    mu_post_CESM_2PIC_SAT_D47_T - stats.t.ppf(1 - 0.025, (n_update_CESM_2PIC_D47 + n_models_CESM_2PIC_monthly)) * std_post_CESM_2PIC_SAT_D47_T / np.sqrt(n_update_CESM_2PIC_D47 + n_models_CESM_2PIC_monthly),
    mu_post_CESM_2PIC_SAT_D47_T + stats.t.ppf(1 - 0.025, (n_update_CESM_2PIC_D47 + n_models_CESM_2PIC_monthly)) * std_post_CESM_2PIC_SAT_D47_T / np.sqrt(n_update_CESM_2PIC_D47 + n_models_CESM_2PIC_monthly),
    color='r', alpha=0.2, label='95% Confidence Interval')

# Layout for SAT panel
axs[0, 1].set_title('CESM 2x preindustrial pCO2')
axs[0, 1].set_xlabel('Month')
axs[0, 1].set_ylabel('Surface Air Temperature (°C)')
# axs[0, 1].legend(loc='upper left')
axs[0, 1].grid(True)
axs[0, 1].set_xticks(months_scale, month_names, rotation=45, ha="right")

# FOURTH PANEL: precip Results
# PRIOR
axs[1, 1].plot(months_scale, mu_prior_CESM_2PIC_precip_monthly, label='Prior Mean', color='b', marker='o')
axs[1, 1].fill_between(months_scale,
    mu_prior_CESM_2PIC_precip_monthly - stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_precip_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
    mu_prior_CESM_2PIC_precip_monthly + stats.t.ppf(1 - 0.025, n_models_CESM_2PIC_monthly) * std_prior_CESM_2PIC_precip_monthly / np.sqrt(n_models_CESM_2PIC_monthly),
    color='b', alpha=0.2, label='95% Confidence Interval')

# POSTERIOR
axs[1, 1].plot(months_scale, mu_post_CESM_2PIC_precip, label='Posterior Mean', color='r', marker='o')
axs[1, 1].fill_between(months_scale,
    mu_post_CESM_2PIC_precip - stats.t.ppf(1 - 0.025, (n_update_CESM_2PIC_d18Oc + n_models_CESM_2PIC_monthly)) * std_post_CESM_2PIC_precip / np.sqrt(n_update_CESM_2PIC_d18Oc + n_models_CESM_2PIC_monthly),
    mu_post_CESM_2PIC_precip + stats.t.ppf(1 - 0.025, (n_update_CESM_2PIC_d18Oc + n_models_CESM_2PIC_monthly)) * std_post_CESM_2PIC_precip / np.sqrt(n_update_CESM_2PIC_d18Oc + n_models_CESM_2PIC_monthly),
    color='r', alpha=0.2, label='95% Confidence Interval')

# Layout for precip panel
# axs[1, 1].set_title('monthly Sea Surface Salinity (precip)')
axs[1, 1].set_xlabel('Month')
axs[1, 1].set_ylabel('Precipitation (mm/day)')
# axs[1, 1].legend(loc='upper left')
axs[1, 1].grid(True)
axs[1, 1].set_xticks(months_scale, month_names, rotation=45, ha="right")

# Next panels similar but for HadCM (new) with 1x preindustrial pCO2 forcing

# SAT Results
# PRIOR
axs[0, 2].plot(months_scale, mu_prior_HadCM_new_1PIC_SAT_monthly, label='Prior Mean', color='b', marker='o')
axs[0, 2].fill_between(months_scale,
    mu_prior_HadCM_new_1PIC_SAT_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_1PIC_monthly) * std_prior_HadCM_new_1PIC_SAT_monthly / np.sqrt(n_models_HadCM_new_1PIC_monthly),
    mu_prior_HadCM_new_1PIC_SAT_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_1PIC_monthly) * std_prior_HadCM_new_1PIC_SAT_monthly / np.sqrt(n_models_HadCM_new_1PIC_monthly),
    color='b', alpha=0.2, label='95% Confidence Interval')

# LIKELIHOOD
axs[0, 2].plot(months_scale, mu_likelihood_T, label='Likelihood Mean', color='y', marker='o')
axs[0, 2].fill_between(months_scale,
    mu_likelihood_T - stats.t.ppf(1 - 0.025, n_update_HadCM_new_1PIC_D47) * std_likelihood_T / np.sqrt(n_update_HadCM_new_1PIC_D47),
    mu_likelihood_T + stats.t.ppf(1 - 0.025, n_update_HadCM_new_1PIC_D47) * std_likelihood_T / np.sqrt(n_update_HadCM_new_1PIC_D47),
    color='y', alpha=0.2, label='95% Confidence Interval')

# POSTERIOR
axs[0, 2].plot(months_scale, mu_post_HadCM_new_1PIC_SAT_D47_T, label='Posterior Mean', color='r', marker='o')
axs[0, 2].fill_between(months_scale,
    mu_post_HadCM_new_1PIC_SAT_D47_T - stats.t.ppf(1 - 0.025, (n_update_HadCM_new_1PIC_D47 + n_models_HadCM_new_1PIC_monthly)) * std_post_HadCM_new_1PIC_SAT_D47_T / np.sqrt(n_update_HadCM_new_1PIC_D47 + n_models_HadCM_new_1PIC_monthly),
    mu_post_HadCM_new_1PIC_SAT_D47_T + stats.t.ppf(1 - 0.025, (n_update_HadCM_new_1PIC_D47 + n_models_HadCM_new_1PIC_monthly)) * std_post_HadCM_new_1PIC_SAT_D47_T / np.sqrt(n_update_HadCM_new_1PIC_D47 + n_models_HadCM_new_1PIC_monthly),
    color='r', alpha=0.2, label='95% Confidence Interval')

# Layout for SAT panel
axs[0, 2].set_title('HadCM 1x preindustrial pCO2')
axs[0, 2].set_xlabel('Month')
axs[0, 2].set_ylabel('Surface Air Temperature (°C)')
# axs[0, 2].legend(loc='upper left')
axs[0, 2].grid(True)
axs[0, 2].set_xticks(months_scale, month_names, rotation=45, ha="right")

# precip Results
# PRIOR
axs[1, 2].plot(months_scale, mu_prior_HadCM_new_1PIC_precip_monthly, label='Prior Mean', color='b', marker='o')
axs[1, 2].fill_between(months_scale,
    mu_prior_HadCM_new_1PIC_precip_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_1PIC_monthly) * std_prior_HadCM_new_1PIC_precip_monthly / np.sqrt(n_models_HadCM_new_1PIC_monthly),
    mu_prior_HadCM_new_1PIC_precip_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_1PIC_monthly) * std_prior_HadCM_new_1PIC_precip_monthly / np.sqrt(n_models_HadCM_new_1PIC_monthly),
    color='b', alpha=0.2, label='95% Confidence Interval')

# POSTERIOR
axs[1, 2].plot(months_scale, mu_post_HadCM_new_1PIC_precip, label='Posterior Mean', color='r', marker='o')
axs[1, 2].fill_between(months_scale,
    mu_post_HadCM_new_1PIC_precip - stats.t.ppf(1 - 0.025, (n_update_HadCM_new_1PIC_d18Oc + n_models_HadCM_new_1PIC_monthly)) * std_post_HadCM_new_1PIC_precip / np.sqrt(n_update_HadCM_new_1PIC_d18Oc + n_models_HadCM_new_1PIC_monthly),
    mu_post_HadCM_new_1PIC_precip + stats.t.ppf(1 - 0.025, (n_update_HadCM_new_1PIC_d18Oc + n_models_HadCM_new_1PIC_monthly)) * std_post_HadCM_new_1PIC_precip / np.sqrt(n_update_HadCM_new_1PIC_d18Oc + n_models_HadCM_new_1PIC_monthly),
    color='r', alpha=0.2, label='95% Confidence Interval')

# Layout for precip panel
# axs[1, 2].set_title('monthly Sea Surface Salinity (precip)')
axs[1, 2].set_xlabel('Month')
axs[1, 2].set_ylabel('Precipitation (mm/day)')
# axs[1, 2].legend(loc='upper left')
axs[1, 2].grid(True)
axs[1, 2].set_xticks(months_scale, month_names, rotation=45, ha="right")

# Next panels similar but for HadCM (new) with 2x preindustrial pCO2 forcing

# SAT Results
# PRIOR
axs[0, 3].plot(months_scale, mu_prior_HadCM_new_2PIC_SAT_monthly, label='Prior Mean', color='b', marker='o')
axs[0, 3].fill_between(months_scale,
    mu_prior_HadCM_new_2PIC_SAT_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_2PIC_monthly) * std_prior_HadCM_new_2PIC_SAT_monthly / np.sqrt(n_models_HadCM_new_2PIC_monthly),
    mu_prior_HadCM_new_2PIC_SAT_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_2PIC_monthly) * std_prior_HadCM_new_2PIC_SAT_monthly / np.sqrt(n_models_HadCM_new_2PIC_monthly),
    color='b', alpha=0.2, label='95% Confidence Interval')

# LIKELIHOOD
axs[0, 3].plot(months_scale, mu_likelihood_T, label='Likelihood Mean', color='y', marker='o')
axs[0, 3].fill_between(months_scale,
    mu_likelihood_T - stats.t.ppf(1 - 0.025, n_update_HadCM_new_2PIC_D47) * std_likelihood_T / np.sqrt(n_update_HadCM_new_2PIC_D47),
    mu_likelihood_T + stats.t.ppf(1 - 0.025, n_update_HadCM_new_2PIC_D47) * std_likelihood_T / np.sqrt(n_update_HadCM_new_2PIC_D47),
    color='y', alpha=0.2, label='95% Confidence Interval')

# POSTERIOR
axs[0, 3].plot(months_scale, mu_post_HadCM_new_2PIC_SAT_D47_T, label='Posterior Mean', color='r', marker='o')
axs[0, 3].fill_between(months_scale,
    mu_post_HadCM_new_2PIC_SAT_D47_T - stats.t.ppf(1 - 0.025, (n_update_HadCM_new_2PIC_D47 + n_models_HadCM_new_2PIC_monthly)) * std_post_HadCM_new_2PIC_SAT_D47_T / np.sqrt(n_update_HadCM_new_2PIC_D47 + n_models_HadCM_new_2PIC_monthly),
    mu_post_HadCM_new_2PIC_SAT_D47_T + stats.t.ppf(1 - 0.025, (n_update_HadCM_new_2PIC_D47 + n_models_HadCM_new_2PIC_monthly)) * std_post_HadCM_new_2PIC_SAT_D47_T / np.sqrt(n_update_HadCM_new_2PIC_D47 + n_models_HadCM_new_2PIC_monthly),
    color='r', alpha=0.2, label='95% Confidence Interval')

# Layout for SAT panel
axs[0, 3].set_title('HadCM 2x preindustrial pCO2')
axs[0, 3].set_xlabel('Month')
axs[0, 3].set_ylabel('Surface Air Temperature (°C)')
# axs[0, 3].legend(loc='upper left')
axs[0, 3].grid(True)
axs[0, 3].set_xticks(months_scale, month_names, rotation=45, ha="right")

# precip Results
# PRIOR
axs[1, 3].plot(months_scale, mu_prior_HadCM_new_2PIC_precip_monthly, label='Prior Mean', color='b', marker='o')
axs[1, 3].fill_between(months_scale,
    mu_prior_HadCM_new_2PIC_precip_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_2PIC_monthly) * std_prior_HadCM_new_2PIC_precip_monthly / np.sqrt(n_models_HadCM_new_2PIC_monthly),
    mu_prior_HadCM_new_2PIC_precip_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_2PIC_monthly) * std_prior_HadCM_new_2PIC_precip_monthly / np.sqrt(n_models_HadCM_new_2PIC_monthly),
    color='b', alpha=0.2, label='95% Confidence Interval')

# POSTERIOR
axs[1, 3].plot(months_scale, mu_post_HadCM_new_2PIC_precip, label='Posterior Mean', color='r', marker='o')
axs[1, 3].fill_between(months_scale,
    mu_post_HadCM_new_2PIC_precip - stats.t.ppf(1 - 0.025, (n_update_HadCM_new_2PIC_d18Oc + n_models_HadCM_new_2PIC_monthly)) * std_post_HadCM_new_2PIC_precip / np.sqrt(n_update_HadCM_new_2PIC_d18Oc + n_models_HadCM_new_2PIC_monthly),
    mu_post_HadCM_new_2PIC_precip + stats.t.ppf(1 - 0.025, (n_update_HadCM_new_2PIC_d18Oc + n_models_HadCM_new_2PIC_monthly)) * std_post_HadCM_new_2PIC_precip / np.sqrt(n_update_HadCM_new_2PIC_d18Oc + n_models_HadCM_new_2PIC_monthly),
    color='r', alpha=0.2, label='95% Confidence Interval')

# Layout for precip panel
# axs[1, 3].set_title('monthly Sea Surface Salinity (precip)')
axs[1, 3].set_xlabel('Month')
axs[1, 3].set_ylabel('Precipitation (mm/day)')
# axs[1, 3].legend(loc='upper left')
axs[1, 3].grid(True)
axs[1, 3].set_xticks(months_scale, month_names, rotation=45, ha="right")


# Next panels similar but for HadCM (new) with 1056 ppm pCO2 forcing

# SAT Results
# PRIOR
axs[0, 4].plot(months_scale, mu_prior_HadCM_new_1056ppm_SAT_monthly, label='Prior Mean', color='b', marker='o')
axs[0, 4].fill_between(months_scale,
    mu_prior_HadCM_new_1056ppm_SAT_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_1056ppm_monthly) * std_prior_HadCM_new_1056ppm_SAT_monthly / np.sqrt(n_models_HadCM_new_1056ppm_monthly),
    mu_prior_HadCM_new_1056ppm_SAT_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_1056ppm_monthly) * std_prior_HadCM_new_1056ppm_SAT_monthly / np.sqrt(n_models_HadCM_new_1056ppm_monthly),
    color='b', alpha=0.2, label='95% Confidence Interval')

# LIKELIHOOD
axs[0, 4].plot(months_scale, mu_likelihood_T, label='Likelihood Mean', color='y', marker='o')
axs[0, 4].fill_between(months_scale,
    mu_likelihood_T - stats.t.ppf(1 - 0.025, n_update_HadCM_new_1056ppm_D47) * std_likelihood_T / np.sqrt(n_update_HadCM_new_1056ppm_D47),
    mu_likelihood_T + stats.t.ppf(1 - 0.025, n_update_HadCM_new_1056ppm_D47) * std_likelihood_T / np.sqrt(n_update_HadCM_new_1056ppm_D47),
    color='y', alpha=0.2, label='95% Confidence Interval')

# POSTERIOR
axs[0, 4].plot(months_scale, mu_post_HadCM_new_1056ppm_SAT_D47_T, label='Posterior Mean', color='r', marker='o')
axs[0, 4].fill_between(months_scale,
    mu_post_HadCM_new_1056ppm_SAT_D47_T - stats.t.ppf(1 - 0.025, (n_update_HadCM_new_1056ppm_D47 + n_models_HadCM_new_1056ppm_monthly)) * std_post_HadCM_new_1056ppm_SAT_D47_T / np.sqrt(n_update_HadCM_new_1056ppm_D47 + n_models_HadCM_new_1056ppm_monthly),
    mu_post_HadCM_new_1056ppm_SAT_D47_T + stats.t.ppf(1 - 0.025, (n_update_HadCM_new_1056ppm_D47 + n_models_HadCM_new_1056ppm_monthly)) * std_post_HadCM_new_1056ppm_SAT_D47_T / np.sqrt(n_update_HadCM_new_1056ppm_D47 + n_models_HadCM_new_1056ppm_monthly),
    color='r', alpha=0.2, label='95% Confidence Interval')

# Layout for SAT panel
axs[0, 4].set_title('HadCM (new) 1056 ppm pCO2')
axs[0, 4].set_xlabel('Month')
axs[0, 4].set_ylabel('Surface Air Temperature (°C)')
# axs[0, 4].legend(loc='upper left')
axs[0, 4].grid(True)
axs[0, 4].set_xticks(months_scale, month_names, rotation=45, ha="right")

# precip Results
# PRIOR
axs[1, 4].plot(months_scale, mu_prior_HadCM_new_1056ppm_precip_monthly, label='Prior Mean', color='b', marker='o')
axs[1, 4].fill_between(months_scale,
    mu_prior_HadCM_new_1056ppm_precip_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_new_1056ppm_monthly) * std_prior_HadCM_new_1056ppm_precip_monthly / np.sqrt(n_models_HadCM_new_1056ppm_monthly),
    mu_prior_HadCM_new_1056ppm_precip_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_new_1056ppm_monthly) * std_prior_HadCM_new_1056ppm_precip_monthly / np.sqrt(n_models_HadCM_new_1056ppm_monthly),
    color='b', alpha=0.2, label='95% Confidence Interval')

# POSTERIOR
axs[1, 4].plot(months_scale, mu_post_HadCM_new_1056ppm_precip, label='Posterior Mean', color='r', marker='o')
axs[1, 4].fill_between(months_scale,
    mu_post_HadCM_new_1056ppm_precip - stats.t.ppf(1 - 0.025, (n_update_HadCM_new_1056ppm_d18Oc + n_models_HadCM_new_1056ppm_monthly)) * std_post_HadCM_new_1056ppm_precip / np.sqrt(n_update_HadCM_new_1056ppm_d18Oc + n_models_HadCM_new_1056ppm_monthly),
    mu_post_HadCM_new_1056ppm_precip + stats.t.ppf(1 - 0.025, (n_update_HadCM_new_1056ppm_d18Oc + n_models_HadCM_new_1056ppm_monthly)) * std_post_HadCM_new_1056ppm_precip / np.sqrt(n_update_HadCM_new_1056ppm_d18Oc + n_models_HadCM_new_1056ppm_monthly),
    color='r', alpha=0.2, label='95% Confidence Interval')

# Layout for precip panel
# axs[1, 4].set_title('monthly Sea Surface Salinity (precip)')
axs[1, 4].set_xlabel('Month')
axs[1, 4].set_ylabel('Precipitation (mm/day)')
# axs[1, 4].legend(loc='upper left')
axs[1, 4].grid(True)
axs[1, 4].set_xticks(months_scale, month_names, rotation=45, ha="right")

# Next panels similar but for HadCM (old) with 2x preindustrial pCO2 forcing

# SAT Results
# PRIOR
axs[0, 5].plot(months_scale, mu_prior_HadCM_old_2PIC_SAT_monthly, label='Prior Mean', color='b', marker='o')
axs[0, 5].fill_between(months_scale,
    mu_prior_HadCM_old_2PIC_SAT_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_old_2PIC_monthly) * std_prior_HadCM_old_2PIC_SAT_monthly / np.sqrt(n_models_HadCM_old_2PIC_monthly),
    mu_prior_HadCM_old_2PIC_SAT_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_old_2PIC_monthly) * std_prior_HadCM_old_2PIC_SAT_monthly / np.sqrt(n_models_HadCM_old_2PIC_monthly),
    color='b', alpha=0.2, label='95% Confidence Interval')

# LIKELIHOOD
axs[0, 5].plot(months_scale, mu_likelihood_T, label='Likelihood Mean', color='y', marker='o')
axs[0, 5].fill_between(months_scale,
    mu_likelihood_T - stats.t.ppf(1 - 0.025, n_update_HadCM_old_2PIC_D47) * std_likelihood_T / np.sqrt(n_update_HadCM_old_2PIC_D47),
    mu_likelihood_T + stats.t.ppf(1 - 0.025, n_update_HadCM_old_2PIC_D47) * std_likelihood_T / np.sqrt(n_update_HadCM_old_2PIC_D47),
    color='y', alpha=0.2, label='95% Confidence Interval')

# POSTERIOR
axs[0, 5].plot(months_scale, mu_post_HadCM_old_2PIC_SAT_D47_T, label='Posterior Mean', color='r', marker='o')
axs[0, 5].fill_between(months_scale,
    mu_post_HadCM_old_2PIC_SAT_D47_T - stats.t.ppf(1 - 0.025, (n_update_HadCM_old_2PIC_D47 + n_models_HadCM_old_2PIC_monthly)) * std_post_HadCM_old_2PIC_SAT_D47_T / np.sqrt(n_update_HadCM_old_2PIC_D47 + n_models_HadCM_old_2PIC_monthly),
    mu_post_HadCM_old_2PIC_SAT_D47_T + stats.t.ppf(1 - 0.025, (n_update_HadCM_old_2PIC_D47 + n_models_HadCM_old_2PIC_monthly)) * std_post_HadCM_old_2PIC_SAT_D47_T / np.sqrt(n_update_HadCM_old_2PIC_D47 + n_models_HadCM_old_2PIC_monthly),
    color='r', alpha=0.2, label='95% Confidence Interval')

# Layout for SAT panel
axs[0, 5].set_title('HadCM (old) 2x preindustrial pCO2')
axs[0, 5].set_xlabel('Month')
axs[0, 5].set_ylabel('Surface Air Temperature (°C)')
# axs[0, 5].legend(loc='upper left')
axs[0, 5].grid(True)
axs[0, 5].set_xticks(months_scale, month_names, rotation=45, ha="right")

# precip Results
# PRIOR
axs[1, 5].plot(months_scale, mu_prior_HadCM_old_2PIC_precip_monthly, label='Prior Mean', color='b', marker='o')
axs[1, 5].fill_between(months_scale,
    mu_prior_HadCM_old_2PIC_precip_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_old_2PIC_monthly) * std_prior_HadCM_old_2PIC_precip_monthly / np.sqrt(n_models_HadCM_old_2PIC_monthly),
    mu_prior_HadCM_old_2PIC_precip_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_old_2PIC_monthly) * std_prior_HadCM_old_2PIC_precip_monthly / np.sqrt(n_models_HadCM_old_2PIC_monthly),
    color='b', alpha=0.2, label='95% Confidence Interval')

# POSTERIOR
axs[1, 5].plot(months_scale, mu_post_HadCM_old_2PIC_precip, label='Posterior Mean', color='r', marker='o')
axs[1, 5].fill_between(months_scale,
    mu_post_HadCM_old_2PIC_precip - stats.t.ppf(1 - 0.025, (n_update_HadCM_old_2PIC_d18Oc + n_models_HadCM_old_2PIC_monthly)) * std_post_HadCM_old_2PIC_precip / np.sqrt(n_update_HadCM_old_2PIC_d18Oc + n_models_HadCM_old_2PIC_monthly),
    mu_post_HadCM_old_2PIC_precip + stats.t.ppf(1 - 0.025, (n_update_HadCM_old_2PIC_d18Oc + n_models_HadCM_old_2PIC_monthly)) * std_post_HadCM_old_2PIC_precip / np.sqrt(n_update_HadCM_old_2PIC_d18Oc + n_models_HadCM_old_2PIC_monthly),
    color='r', alpha=0.2, label='95% Confidence Interval')

# Layout for precip panel
# axs[1, 5].set_title('monthly Sea Surface Salinity (precip)')
axs[1, 5].set_xlabel('Month')
axs[1, 5].set_ylabel('Precipitation (mm/day)')
# axs[1, 5].legend(loc='upper left')
axs[1, 5].grid(True)
axs[1, 5].set_xticks(months_scale, month_names, rotation=45, ha="right")


# Next panels similar but for HadCM (old) with 2x preindustrial pCO2 forcing

# SAT Results
# PRIOR
axs[0, 6].plot(months_scale, mu_prior_HadCM_old_4PIC_SAT_monthly, label='Prior Mean', color='b', marker='o')
axs[0, 6].fill_between(months_scale,
    mu_prior_HadCM_old_4PIC_SAT_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_old_4PIC_monthly) * std_prior_HadCM_old_4PIC_SAT_monthly / np.sqrt(n_models_HadCM_old_4PIC_monthly),
    mu_prior_HadCM_old_4PIC_SAT_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_old_4PIC_monthly) * std_prior_HadCM_old_4PIC_SAT_monthly / np.sqrt(n_models_HadCM_old_4PIC_monthly),
    color='b', alpha=0.2, label='95% Confidence Interval')

# LIKELIHOOD
axs[0, 6].plot(months_scale, mu_likelihood_T, label='Likelihood Mean', color='y', marker='o')
axs[0, 6].fill_between(months_scale,
    mu_likelihood_T - stats.t.ppf(1 - 0.025, n_update_HadCM_old_4PIC_D47) * std_likelihood_T / np.sqrt(n_update_HadCM_old_4PIC_D47),
    mu_likelihood_T + stats.t.ppf(1 - 0.025, n_update_HadCM_old_4PIC_D47) * std_likelihood_T / np.sqrt(n_update_HadCM_old_4PIC_D47),
    color='y', alpha=0.2, label='95% Confidence Interval')

# POSTERIOR
axs[0, 6].plot(months_scale, mu_post_HadCM_old_4PIC_SAT_D47_T, label='Posterior Mean', color='r', marker='o')
axs[0, 6].fill_between(months_scale,
    mu_post_HadCM_old_4PIC_SAT_D47_T - stats.t.ppf(1 - 0.025, (n_update_HadCM_old_4PIC_D47 + n_models_HadCM_old_4PIC_monthly)) * std_post_HadCM_old_4PIC_SAT_D47_T / np.sqrt(n_update_HadCM_old_4PIC_D47 + n_models_HadCM_old_4PIC_monthly),
    mu_post_HadCM_old_4PIC_SAT_D47_T + stats.t.ppf(1 - 0.025, (n_update_HadCM_old_4PIC_D47 + n_models_HadCM_old_4PIC_monthly)) * std_post_HadCM_old_4PIC_SAT_D47_T / np.sqrt(n_update_HadCM_old_4PIC_D47 + n_models_HadCM_old_4PIC_monthly),
    color='r', alpha=0.2, label='95% Confidence Interval')

# Layout for SAT panel
axs[0, 6].set_title('HadCM (old) 4x preindustrial pCO2')
axs[0, 6].set_xlabel('Month')
axs[0, 6].set_ylabel('Surface Air Temperature (°C)')
axs[0, 6].legend(loc='upper left')
axs[0, 6].grid(True)
axs[0, 6].set_xticks(months_scale, month_names, rotation=45, ha="right")

# precip Results
# PRIOR
axs[1, 6].plot(months_scale, mu_prior_HadCM_old_4PIC_precip_monthly, label='Prior Mean', color='b', marker='o')
axs[1, 6].fill_between(months_scale,
    mu_prior_HadCM_old_4PIC_precip_monthly - stats.t.ppf(1 - 0.025, n_models_HadCM_old_4PIC_monthly) * std_prior_HadCM_old_4PIC_precip_monthly / np.sqrt(n_models_HadCM_old_4PIC_monthly),
    mu_prior_HadCM_old_4PIC_precip_monthly + stats.t.ppf(1 - 0.025, n_models_HadCM_old_4PIC_monthly) * std_prior_HadCM_old_4PIC_precip_monthly / np.sqrt(n_models_HadCM_old_4PIC_monthly),
    color='b', alpha=0.2, label='95% Confidence Interval')

# POSTERIOR
axs[1, 6].plot(months_scale, mu_post_HadCM_old_4PIC_precip, label='Posterior Mean', color='r', marker='o')
axs[1, 6].fill_between(months_scale,
    mu_post_HadCM_old_4PIC_precip - stats.t.ppf(1 - 0.025, (n_update_HadCM_old_4PIC_d18Oc + n_models_HadCM_old_4PIC_monthly)) * std_post_HadCM_old_4PIC_precip / np.sqrt(n_update_HadCM_old_4PIC_d18Oc + n_models_HadCM_old_4PIC_monthly),
    mu_post_HadCM_old_4PIC_precip + stats.t.ppf(1 - 0.025, (n_update_HadCM_old_4PIC_d18Oc + n_models_HadCM_old_4PIC_monthly)) * std_post_HadCM_old_4PIC_precip / np.sqrt(n_update_HadCM_old_4PIC_d18Oc + n_models_HadCM_old_4PIC_monthly),
    color='r', alpha=0.2, label='95% Confidence Interval')

# Layout for precip panel
# axs[1, 6].set_title('monthly Sea Surface Salinity (precip)')
axs[1, 6].set_xlabel('Month')
axs[1, 6].set_ylabel('Precipitation (mm/day)')
axs[1, 6].legend(loc='upper left')
axs[1, 6].grid(True)
axs[1, 6].set_xticks(months_scale, month_names, rotation=45, ha="right")

# Shared x-axis labels
plt.xticks(months_scale, month_names, rotation=45, ha="right")
plt.suptitle('Seasonal Surface Air Temperature (SAT) and precipitation outcomes for all model scenarios', fontsize=16)
plt.tight_layout()
plt.show()
No description has been provided for this image

Final plot for pCO2 and inter-model comparison¶

Aggregate statistics on posterior outcomes on SST and SAT for all cases¶

In [80]:
# Prepare the data for the table
data = {
    "Data Type": [
        "Prior CESM 2PIC",
        "Prior CESM 4PIC",
        "Prior HadCM (new) 1PIC",
        "Prior HadCM (new) 2PIC",
        "Prior HadCM (new) 1056ppm",
        "Prior HadCM (old) 2PIC",
        "Prior HadCM (old) 4PIC",
        "Likelihood Measurements",
        "Posterior CESM 2PIC",
        "Posterior CESM 4PIC",
        "Posterior HadCM (new) 1PIC",
        "Posterior HadCM (new) 2PIC",
        "Posterior HadCM (new) 1056ppm",
        "Posterior HadCM (old) 2PIC",
        "Posterior HadCM (old) 4PIC"
    ]
}

# Add monthly means and standard deviations to the data dictionary
months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]

# Process and rename the means and standard deviations for each data source
SST_means_prior_CESM_2PIC = D47c.OGLS23.T47(D47 = mu_prior_CESM_2PIC_SST_D47_monthly_original, sD47 = cov_prior_CESM_2PIC_SST_D47_monthly_original, return_covar = True)[0]
SST_stds_prior_CESM_2PIC = np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_prior_CESM_2PIC_SST_D47_monthly_original, sD47 = cov_prior_CESM_2PIC_SST_D47_monthly_original, return_covar = True)[1]))
SST_means_prior_CESM_4PIC = D47c.OGLS23.T47(D47 = mu_prior_CESM_4PIC_SST_D47_monthly_original, sD47 = cov_prior_CESM_4PIC_SST_D47_monthly_original, return_covar = True)[0]
SST_stds_prior_CESM_4PIC = np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_prior_CESM_4PIC_SST_D47_monthly_original, sD47 = cov_prior_CESM_4PIC_SST_D47_monthly_original, return_covar = True)[1]))
SST_means_prior_HadCM_new_1PIC = D47c.OGLS23.T47(D47 = mu_prior_HadCM_new_1PIC_SST_D47_monthly, sD47 = cov_prior_HadCM_new_1PIC_SST_D47_monthly, return_covar = True)[0]
SST_stds_prior_HadCM_new_1PIC = np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_prior_HadCM_new_1PIC_SST_D47_monthly, sD47 = cov_prior_HadCM_new_1PIC_SST_D47_monthly, return_covar = True)[1]))
SST_means_prior_HadCM_new_2PIC = D47c.OGLS23.T47(D47 = mu_prior_HadCM_new_2PIC_SST_D47_monthly, sD47 = cov_prior_HadCM_new_2PIC_SST_D47_monthly, return_covar = True)[0]
SST_stds_prior_HadCM_new_2PIC = np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_prior_HadCM_new_2PIC_SST_D47_monthly, sD47 = cov_prior_HadCM_new_2PIC_SST_D47_monthly, return_covar = True)[1]))
SST_means_prior_HadCM_new_1056ppm = D47c.OGLS23.T47(D47 = mu_prior_HadCM_new_1056ppm_SST_D47_monthly, sD47 = cov_prior_HadCM_new_1056ppm_SST_D47_monthly, return_covar = True)[0]
SST_stds_prior_HadCM_new_1056ppm = np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_prior_HadCM_new_1056ppm_SST_D47_monthly, sD47 = cov_prior_HadCM_new_1056ppm_SST_D47_monthly, return_covar = True)[1]))
SST_means_prior_HadCM_old_2PIC = D47c.OGLS23.T47(D47 = mu_prior_HadCM_old_2PIC_SST_D47_monthly, sD47 = cov_prior_HadCM_old_2PIC_SST_D47_monthly, return_covar = True)[0]
SST_stds_prior_HadCM_old_2PIC = np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_prior_HadCM_old_2PIC_SST_D47_monthly, sD47 = cov_prior_HadCM_old_2PIC_SST_D47_monthly, return_covar = True)[1]))
SST_means_prior_HadCM_old_4PIC = D47c.OGLS23.T47(D47 = mu_prior_HadCM_old_4PIC_SST_D47_monthly, sD47 = cov_prior_HadCM_old_4PIC_SST_D47_monthly, return_covar = True)[0]
SST_stds_prior_HadCM_old_4PIC = np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_prior_HadCM_old_4PIC_SST_D47_monthly, sD47 = cov_prior_HadCM_old_4PIC_SST_D47_monthly, return_covar = True)[1]))

SST_likelihood_means = D47c.OGLS23.T47(D47 = mu_likelihood[var_start_D47_monthly:var_end_D47_monthly], sD47 = std_likelihood[var_start_D47_monthly:var_end_D47_monthly], return_covar = True)[0]
SST_likelihood_stds =  np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_likelihood[var_start_D47_monthly:var_end_D47_monthly], sD47 = std_likelihood[var_start_D47_monthly:var_end_D47_monthly], return_covar = True)[1]))

SST_means_post_CESM_2PIC = D47c.OGLS23.T47(D47 = mu_post_CESM_2PIC_SST_D47, sD47 = cov_post_CESM_2PIC_SST_D47, return_covar = True)[0]
SST_stds_post_CESM_2PIC = np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_post_CESM_2PIC_SST_D47, sD47 = cov_post_CESM_2PIC_SST_D47, return_covar = True)[1]))
SST_means_post_CESM_4PIC = D47c.OGLS23.T47(D47 = mu_post_CESM_4PIC_SST_D47, sD47 = cov_post_CESM_4PIC_SST_D47, return_covar = True)[0]
SST_stds_post_CESM_4PIC = np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_post_CESM_4PIC_SST_D47, sD47 = cov_post_CESM_4PIC_SST_D47, return_covar = True)[1]))
SST_means_post_HadCM_new_1PIC = D47c.OGLS23.T47(D47 = mu_post_HadCM_new_1PIC_SST_D47, sD47 = cov_post_HadCM_new_1PIC_SST_D47, return_covar = True)[0]
SST_stds_post_HadCM_new_1PIC = np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_post_HadCM_new_1PIC_SST_D47, sD47 = cov_post_HadCM_new_1PIC_SST_D47, return_covar = True)[1]))
SST_means_post_HadCM_new_2PIC = D47c.OGLS23.T47(D47 = mu_post_HadCM_new_2PIC_SST_D47, sD47 = cov_post_HadCM_new_2PIC_SST_D47, return_covar = True)[0]
SST_stds_post_HadCM_new_2PIC = np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_post_HadCM_new_2PIC_SST_D47, sD47 = cov_post_HadCM_new_2PIC_SST_D47, return_covar = True)[1]))
SST_means_post_HadCM_new_1056ppm = D47c.OGLS23.T47(D47 = mu_post_HadCM_new_1056ppm_SST_D47, sD47 = cov_post_HadCM_new_1056ppm_SST_D47, return_covar = True)[0]
SST_stds_post_HadCM_new_1056ppm = np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_post_HadCM_new_1056ppm_SST_D47, sD47 = cov_post_HadCM_new_1056ppm_SST_D47, return_covar = True)[1]))
SST_means_post_HadCM_old_2PIC = D47c.OGLS23.T47(D47 = mu_post_HadCM_old_2PIC_SST_D47, sD47 = cov_post_HadCM_old_2PIC_SST_D47, return_covar = True)[0]
SST_stds_post_HadCM_old_2PIC = np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_post_HadCM_old_2PIC_SST_D47, sD47 = cov_post_HadCM_old_2PIC_SST_D47, return_covar = True)[1]))
SST_means_post_HadCM_old_4PIC = D47c.OGLS23.T47(D47 = mu_post_HadCM_old_4PIC_SST_D47, sD47 = cov_post_HadCM_old_4PIC_SST_D47, return_covar = True)[0]
SST_stds_post_HadCM_old_4PIC = np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_post_HadCM_old_4PIC_SST_D47, sD47 = cov_post_HadCM_old_4PIC_SST_D47, return_covar = True)[1]))

# Process and rename the means and standard deviations for each data source
SAT_means_prior_CESM_2PIC = D47c.OGLS23.T47(D47 = mu_prior_CESM_2PIC_SAT_D47_monthly_original, sD47 = cov_prior_CESM_2PIC_SAT_D47_monthly_original, return_covar = True)[0]
SAT_stds_prior_CESM_2PIC = np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_prior_CESM_2PIC_SAT_D47_monthly_original, sD47 = cov_prior_CESM_2PIC_SAT_D47_monthly_original, return_covar = True)[1]))
SAT_means_prior_CESM_4PIC = D47c.OGLS23.T47(D47 = mu_prior_CESM_4PIC_SAT_D47_monthly_original, sD47 = cov_prior_CESM_4PIC_SAT_D47_monthly_original, return_covar = True)[0]
SAT_stds_prior_CESM_4PIC = np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_prior_CESM_4PIC_SAT_D47_monthly_original, sD47 = cov_prior_CESM_4PIC_SAT_D47_monthly_original, return_covar = True)[1]))
SAT_means_prior_HadCM_new_1PIC = D47c.OGLS23.T47(D47 = mu_prior_HadCM_new_1PIC_SAT_D47_monthly, sD47 = cov_prior_HadCM_new_1PIC_SAT_D47_monthly, return_covar = True)[0]
SAT_stds_prior_HadCM_new_1PIC = np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_prior_HadCM_new_1PIC_SAT_D47_monthly, sD47 = cov_prior_HadCM_new_1PIC_SAT_D47_monthly, return_covar = True)[1]))
SAT_means_prior_HadCM_new_2PIC = D47c.OGLS23.T47(D47 = mu_prior_HadCM_new_2PIC_SAT_D47_monthly, sD47 = cov_prior_HadCM_new_2PIC_SAT_D47_monthly, return_covar = True)[0]
SAT_stds_prior_HadCM_new_2PIC = np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_prior_HadCM_new_2PIC_SAT_D47_monthly, sD47 = cov_prior_HadCM_new_2PIC_SAT_D47_monthly, return_covar = True)[1]))
SAT_means_prior_HadCM_new_1056ppm = D47c.OGLS23.T47(D47 = mu_prior_HadCM_new_1056ppm_SAT_D47_monthly, sD47 = cov_prior_HadCM_new_1056ppm_SAT_D47_monthly, return_covar = True)[0]
SAT_stds_prior_HadCM_new_1056ppm = np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_prior_HadCM_new_1056ppm_SAT_D47_monthly, sD47 = cov_prior_HadCM_new_1056ppm_SAT_D47_monthly, return_covar = True)[1]))
SAT_means_prior_HadCM_old_2PIC = D47c.OGLS23.T47(D47 = mu_prior_HadCM_old_2PIC_SAT_D47_monthly, sD47 = cov_prior_HadCM_old_2PIC_SAT_D47_monthly, return_covar = True)[0]
SAT_stds_prior_HadCM_old_2PIC = np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_prior_HadCM_old_2PIC_SAT_D47_monthly, sD47 = cov_prior_HadCM_old_2PIC_SAT_D47_monthly, return_covar = True)[1]))
SAT_means_prior_HadCM_old_4PIC = D47c.OGLS23.T47(D47 = mu_prior_HadCM_old_4PIC_SAT_D47_monthly, sD47 = cov_prior_HadCM_old_4PIC_SAT_D47_monthly, return_covar = True)[0]
SAT_stds_prior_HadCM_old_4PIC = np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_prior_HadCM_old_4PIC_SAT_D47_monthly, sD47 = cov_prior_HadCM_old_4PIC_SAT_D47_monthly, return_covar = True)[1]))

SAT_likelihood_means = D47c.OGLS23.T47(D47 = mu_likelihood[var_start_D47_monthly:var_end_D47_monthly], sD47 = std_likelihood[var_start_D47_monthly:var_end_D47_monthly], return_covar = True)[0]
SAT_likelihood_stds =  np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_likelihood[var_start_D47_monthly:var_end_D47_monthly], sD47 = std_likelihood[var_start_D47_monthly:var_end_D47_monthly], return_covar = True)[1]))

SAT_means_post_CESM_2PIC = D47c.OGLS23.T47(D47 = mu_post_CESM_2PIC_SAT_D47, sD47 = cov_post_CESM_2PIC_SAT_D47, return_covar = True)[0]
SAT_stds_post_CESM_2PIC = np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_post_CESM_2PIC_SAT_D47, sD47 = cov_post_CESM_2PIC_SAT_D47, return_covar = True)[1]))
SAT_means_post_CESM_4PIC = D47c.OGLS23.T47(D47 = mu_post_CESM_4PIC_SAT_D47, sD47 = cov_post_CESM_4PIC_SAT_D47, return_covar = True)[0]
SAT_stds_post_CESM_4PIC = np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_post_CESM_4PIC_SAT_D47, sD47 = cov_post_CESM_4PIC_SAT_D47, return_covar = True)[1]))
SAT_means_post_HadCM_new_1PIC = D47c.OGLS23.T47(D47 = mu_post_HadCM_new_1PIC_SAT_D47, sD47 = cov_post_HadCM_new_1PIC_SAT_D47, return_covar = True)[0]
SAT_stds_post_HadCM_new_1PIC = np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_post_HadCM_new_1PIC_SAT_D47, sD47 = cov_post_HadCM_new_1PIC_SAT_D47, return_covar = True)[1]))
SAT_means_post_HadCM_new_2PIC = D47c.OGLS23.T47(D47 = mu_post_HadCM_new_2PIC_SAT_D47, sD47 = cov_post_HadCM_new_2PIC_SAT_D47, return_covar = True)[0]
SAT_stds_post_HadCM_new_2PIC = np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_post_HadCM_new_2PIC_SAT_D47, sD47 = cov_post_HadCM_new_2PIC_SAT_D47, return_covar = True)[1]))
SAT_means_post_HadCM_new_1056ppm = D47c.OGLS23.T47(D47 = mu_post_HadCM_new_1056ppm_SAT_D47, sD47 = cov_post_HadCM_new_1056ppm_SAT_D47, return_covar = True)[0]
SAT_stds_post_HadCM_new_1056ppm = np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_post_HadCM_new_1056ppm_SAT_D47, sD47 = cov_post_HadCM_new_1056ppm_SAT_D47, return_covar = True)[1]))
SAT_means_post_HadCM_old_2PIC = D47c.OGLS23.T47(D47 = mu_post_HadCM_old_2PIC_SAT_D47, sD47 = cov_post_HadCM_old_2PIC_SAT_D47, return_covar = True)[0]
SAT_stds_post_HadCM_old_2PIC = np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_post_HadCM_old_2PIC_SAT_D47, sD47 = cov_post_HadCM_old_2PIC_SAT_D47, return_covar = True)[1]))
SAT_means_post_HadCM_old_4PIC = D47c.OGLS23.T47(D47 = mu_post_HadCM_old_4PIC_SAT_D47, sD47 = cov_post_HadCM_old_4PIC_SAT_D47, return_covar = True)[0]
SAT_stds_post_HadCM_old_4PIC = np.sqrt(np.diag(D47c.OGLS23.T47(D47 = mu_post_HadCM_old_4PIC_SAT_D47, sD47 = cov_post_HadCM_old_4PIC_SAT_D47, return_covar = True)[1]))

# Combine all means and standard deviations into the data structure
all_SST_means = [
    SST_means_prior_CESM_2PIC,
    SST_means_prior_CESM_4PIC,
    SST_means_prior_HadCM_new_1PIC,
    SST_means_prior_HadCM_new_2PIC,
    SST_means_prior_HadCM_new_1056ppm,
    SST_means_prior_HadCM_old_2PIC,
    SST_means_prior_HadCM_old_4PIC,
    SST_likelihood_means,
    SST_means_post_CESM_2PIC,
    SST_means_post_CESM_4PIC,
    SST_means_post_HadCM_new_1PIC,
    SST_means_post_HadCM_new_2PIC,
    SST_means_post_HadCM_new_1056ppm,
    SST_means_post_HadCM_old_2PIC,
    SST_means_post_HadCM_old_4PIC
]
all_SST_stds = [
    SST_stds_prior_CESM_2PIC,
    SST_stds_prior_CESM_4PIC,
    SST_stds_prior_HadCM_new_1PIC,
    SST_stds_prior_HadCM_new_2PIC,
    SST_stds_prior_HadCM_new_1056ppm,
    SST_stds_prior_HadCM_old_2PIC,
    SST_stds_prior_HadCM_old_4PIC,
    SST_likelihood_stds,
    SST_stds_post_CESM_2PIC,
    SST_stds_post_CESM_4PIC,
    SST_stds_post_HadCM_new_1PIC,
    SST_stds_post_HadCM_new_2PIC,
    SST_stds_post_HadCM_new_1056ppm,
    SST_stds_post_HadCM_old_2PIC,
    SST_stds_post_HadCM_old_4PIC
]

all_SAT_means = [
    SAT_means_prior_CESM_2PIC,
    SAT_means_prior_CESM_4PIC,
    SAT_means_prior_HadCM_new_1PIC,
    SAT_means_prior_HadCM_new_2PIC,
    SAT_means_prior_HadCM_new_1056ppm,
    SAT_means_prior_HadCM_old_2PIC,
    SAT_means_prior_HadCM_old_4PIC,
    SAT_likelihood_means,
    SAT_means_post_CESM_2PIC,
    SAT_means_post_CESM_4PIC,
    SAT_means_post_HadCM_new_1PIC,
    SAT_means_post_HadCM_new_2PIC,
    SAT_means_post_HadCM_new_1056ppm,
    SAT_means_post_HadCM_old_2PIC,
    SAT_means_post_HadCM_old_4PIC
]
all_SAT_stds = [
    SAT_stds_prior_CESM_2PIC,
    SAT_stds_prior_CESM_4PIC,
    SAT_stds_prior_HadCM_new_1PIC,
    SAT_stds_prior_HadCM_new_2PIC,
    SAT_stds_prior_HadCM_new_1056ppm,
    SAT_stds_prior_HadCM_old_2PIC,
    SAT_stds_prior_HadCM_old_4PIC,
    SAT_likelihood_stds,
    SAT_stds_post_CESM_2PIC,
    SAT_stds_post_CESM_4PIC,
    SAT_stds_post_HadCM_new_1PIC,
    SAT_stds_post_HadCM_new_2PIC,
    SAT_stds_post_HadCM_new_1056ppm,
    SAT_stds_post_HadCM_old_2PIC,
    SAT_stds_post_HadCM_old_4PIC
]

# Create a dictionary to store all the data
all_temperature_data = {"Data Type": data["Data Type"]}

# Add SST means and stds
for i, month in enumerate(months):
    all_temperature_data[f"{month} SST Mean"] = [means[i] for means in all_SST_means]
    all_temperature_data[f"{month} SST Std"] = [stds[i] for stds in all_SST_stds]

# Add SAT means and stds
for i, month in enumerate(months):
    all_temperature_data[f"{month} SAT Mean"] = [means[i] for means in all_SAT_means]
    all_temperature_data[f"{month} SAT Std"] = [stds[i] for stds in all_SAT_stds]

# Create the Pandas DataFrame
all_temperature_pCO2_test_table_df = pd.DataFrame(all_temperature_data)

# Set the 'Data Type' column as the index
all_temperature_pCO2_test_table_df = all_temperature_pCO2_test_table_df.set_index("Data Type")

# Export the table to a CSV file
all_temperature_pCO2_test_table_df.to_csv("Sensitivity_test_pCO2_models/all_temperature_pCO2_test_table.csv")

print("Combined data exported to Sensitivity_test_pCO2_models/all_temperature_pCO2_test_table.csv")
Combined data exported to Sensitivity_test_pCO2_models/all_temperature_pCO2_test_table.csv

Combined plot of measurements, priors and posteriors with precision uncertainties for temperature¶

In [81]:
fig, (ax1, ax3) = plt.subplots(
    2, 1, figsize=(10, 8), sharex='col'
)
fig.subplots_adjust(hspace=0.1, wspace=0.25)  # reduce vertical & horizontal spacing

# Define a colormap across all months
cmap = plt.cm.coolwarm
colors = [cmap(i / (len(months)-1)) for i in range(len(months))]
color_dict = dict(zip(months, colors))

# Define offsets for x-axis to avoid overlapping error bars
x_offsets = np.linspace(-0.3, 0.3, len(months))

# Define x values for each data type
x_values = np.arange(len(all_temperature_pCO2_test_table_df.index))

# --- SST plot ---
for month in months:
    ax1.errorbar(
        x = x_values + x_offsets[months.index(month)],
        y = all_temperature_pCO2_test_table_df[f"{month} SST Mean"],
        yerr = all_temperature_pCO2_test_table_df[f"{month} SST Std"],
        capsize = 3,
        fmt='.',
        label=month,
        color=color_dict[month]
    )
# Add light green rectangle to highlight prior
ax1.add_patch(
    Rectangle(
        (-0.5, ax1.get_ylim()[0]),  # (x,y)
        7,                          # width
        ax1.get_ylim()[1] - ax1.get_ylim()[0],  # height
        color='lightgreen',
        alpha=0.3,
    )
)
# Add light blue rectangle to highlight measurement
ax1.add_patch(
    Rectangle(
        (6.5, ax1.get_ylim()[0]),  # (x,y)
        1,                          # width
        ax1.get_ylim()[1] - ax1.get_ylim()[0],  # height
        color='lightblue',
        alpha=0.3,
    )
)
# Add light red rectangle to highlight posteriors
ax1.add_patch(
    Rectangle(
        (7.5, ax1.get_ylim()[0]),  # (x,y)
        7,         # width
        ax1.get_ylim()[1] - ax1.get_ylim()[0],  # height
        color='red',
        alpha=0.1,
    )
)
ax1.set_xticks(x_values)
ax1.set_xticklabels(all_temperature_pCO2_test_table_df.index, rotation=45, ha="right")
# ax1.set_xlabel('test case')
ax1.set_ylabel('SST (degrees C)', color='purple')
ax1.tick_params(axis='y', labelcolor='purple')

# # Secondary axis for temperature
# ax1_temp = ax1.twinx()
# ax1_temp.set_ylabel('SST Temperature (°C)', color='purple')
# ax1_temp.tick_params(axis='y', labelcolor='purple')
# ax1_temp.set_yticks(
#     ticks = D47c.OGLS23.T47(T = np.linspace(0, 50, 25))[0],
#     labels = np.linspace(0, 50, 25).astype(int)
# )
# ax1_temp.set_ylim(ax1.get_ylim())

# --- SAT Plot ---

for month in months:
    ax3.errorbar(
        x = x_values + x_offsets[months.index(month)],
        y = all_temperature_pCO2_test_table_df[f"{month} SAT Mean"],
        yerr = all_temperature_pCO2_test_table_df[f"{month} SAT Std"],
        capsize = 3,
        fmt='.',
        label=month,
        color=color_dict[month]
    )
# Add light green rectangle to highlight prior
ax3.add_patch(
    Rectangle(
        (-0.5, ax3.get_ylim()[0]),  # (x,y)
        7,                          # width
        ax3.get_ylim()[1] - ax3.get_ylim()[0],  # height
        color='lightgreen',
        alpha=0.3,
    )
)
# Add light blue rectangle to highlight measurement
ax3.add_patch(
    Rectangle(
        (6.5, ax3.get_ylim()[0]),  # (x,y)
        1,                          # width
        ax3.get_ylim()[1] - ax3.get_ylim()[0],  # height
        color='lightblue',
        alpha=0.3,
    )
)
# Add light red rectangle to highlight posteriors
ax3.add_patch(
    Rectangle(
        (7.5, ax3.get_ylim()[0]),  # (x,y)
        7,         # width
        ax3.get_ylim()[1] - ax3.get_ylim()[0],  # height
        color='red',
        alpha=0.1,
    )
)
ax3.set_xticks(x_values)
ax3.set_xticklabels(all_temperature_pCO2_test_table_df.index, rotation=45, ha="right")
ax3.set_ylabel('SAT (degrees C)', color='darkblue')
ax3.tick_params(axis='y', labelcolor='darkblue')

# # Secondary axis for temperature, based on d18Oc-temperature conversion used above
# ax3_temp = ax3.twinx()
# ax3_temp.set_ylabel('SAT Temperature (°C; assuming δ18Ow of 0‰)', color='darkblue')
# ax3_temp.tick_params(axis='y', labelcolor='darkblue')
# ax3_temp.set_yticks(
#     ticks = ((20.6 - np.linspace(0, 50, 25)) / 4.34  - 0.27) + 0 + 0.27,
#     labels = np.linspace(0, 50, 25).astype(int)
# )
# ax3_temp.set_ylim(ax3.get_ylim())
# ax3.set_title('SAT value by test case and Month')

# ---------------------------------------------------------
# Shared legend above all plots
handles1, labels1 = ax1.get_legend_handles_labels()
fig.legend(handles1, labels1,
           loc="upper center",
           bbox_to_anchor=(0.5, 0.95),
           ncol=len(months) / 2,
           frameon=False)

plt.tight_layout(rect=[0, 0, 1, 0.9])  # leave space for legend
plt.suptitle('Monthly Surface Temperature (SST and SAT) across all model scenarios', fontsize=16)
plt.show()
No description has been provided for this image